Path: blob/21.2-virgl/src/gallium/auxiliary/tessellator/tessellator.cpp
4565 views
/*1Copyright (c) Microsoft Corporation23Permission is hereby granted, free of charge, to any person obtaining a copy of this software and4associated documentation files (the "Software"), to deal in the Software without restriction,5including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,6and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,7subject to the following conditions:89The above copyright notice and this permission notice shall be included in all copies or substantial10portions of the Software.1112THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT13NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.14IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,15WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE16SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.17*/1819#include "tessellator.hpp"20#include "util/macros.h"21#if defined(_MSC_VER)22#include <math.h> // ceil23#else24#include <cmath>25#endif26#define min(x,y) (x < y ? x : y)27#define max(x,y) (x > y ? x : y)2829//=================================================================================================================================30// Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)31//=================================================================================================================================32//33//---------------------------------------------------------------------------------------------------------------------------------34// isNaN35//---------------------------------------------------------------------------------------------------------------------------------3637union fiu {38float f;39int i;40};4142static bool tess_isNaN( float a )43{44static const int exponentMask = 0x7f800000;45static const int mantissaMask = 0x007fffff;46union fiu fiu;47fiu.f = a;48return ( ( ( fiu.i & exponentMask ) == exponentMask ) && ( fiu.i & mantissaMask ) ); // NaN49}5051//---------------------------------------------------------------------------------------------------------------------------------52// flush (denorm)53//---------------------------------------------------------------------------------------------------------------------------------54static float tess_flush( float a )55{56static const int minNormalizedFloat = 0x00800000;57static const int signBit = 0x80000000;58static const int signBitComplement = 0x7fffffff;59union fiu fiu, uif;60fiu.f = a;61int b = fiu.i & signBitComplement; // fabs()62if( b < minNormalizedFloat ) // UINT comparison. NaN/INF do test false here63{64b = signBit & (fiu.i);65uif.i = b;66return uif.f;67}68return a;69}7071//---------------------------------------------------------------------------------------------------------------------------------72// IEEE754R min73//---------------------------------------------------------------------------------------------------------------------------------74static float tess_fmin( float a, float b )75{76float _a = tess_flush( a );77float _b = tess_flush( b );78if( tess_isNaN( _b ) )79{80return a;81}82else if( ( _a == 0 ) && ( _b == 0 ) )83{84union fiu fiu;85fiu.f = _a;86return ( fiu.i & 0x80000000 ) ? a : b;87}88return _a < _b ? a : b;89}9091//---------------------------------------------------------------------------------------------------------------------------------92// IEEE754R max93//---------------------------------------------------------------------------------------------------------------------------------94static float tess_fmax( float a, float b )95{96float _a = tess_flush( a );97float _b = tess_flush( b );9899if( tess_isNaN( _b ) )100{101return a;102}103else if( ( _a == 0 ) && ( _b == 0 ) )104{105union fiu fiu;106fiu.f = _b;107return ( fiu.i & 0x80000000 ) ? a : b;108}109return _a >= _b ? a : b;110}111112//=================================================================================================================================113// Fixed Point Math114//=================================================================================================================================115116//-----------------------------------------------------------------------------------------------------------------------------117// floatToFixedPoint118//119// Convert 32-bit float to 32-bit fixed point integer, using only120// integer arithmetic + bitwise operations.121//122// c_uIBits: UINT8 : Width of i (aka. integer bits)123// c_uFBits: UINT8 : Width of f (aka. fractional bits)124// c_bSigned: bool : Whether the integer bits are a 2's complement signed value125// input: float : All values valid.126// output: INT32 : At most 24 bits from LSB are meaningful, depending127// on the fixed point bit representation chosen (see128// below). Extra bits are sign extended from the most129// meaningful bit.130//131//-----------------------------------------------------------------------------------------------------------------------------132133typedef unsigned char UINT8;134typedef int INT32;135template< const UINT8 c_uIBits, const UINT8 c_uFBits, const bool c_bSigned >136INT32 floatToIDotF( const float& input )137{138// ------------------------------------------------------------------------139// output fixed point format140// 32-bit result:141//142// [sign-extend]i.f143// | |144// MSB(31)...LSB(0)145//146// f fractional part of the number, an unsigned147// value with _fxpFracBitCount bits (defined below)148//149// . implied decimal150//151// i integer part of the number, a 2's complement152// value with _fxpIntBitCount bits (defined below)153//154// [sign-extend] MSB of i conditionally replicated155//156// ------------------------------------------------------------------------157// Define fixed point bit counts158//159160// Commenting out C_ASSERT below to minimise #includes:161// C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );162163// Define most negative and most positive fixed point values164const INT32 c_iMinResult = (c_bSigned ? INT32( -1 ) << (c_uIBits + c_uFBits - 1) : 0);165const INT32 c_iMaxResult = ~c_iMinResult;166167// ------------------------------------------------------------------------168// constant float properties169// ------------------------------------------------------------------------170const UINT8 _fltMantissaBitCount = 23;171const UINT8 _fltExponentBitCount = 8;172const INT32 _fltExponentBias = (INT32( 1 ) << (_fltExponentBitCount - 1)) - 1;173const INT32 _fltHiddenBit = INT32( 1 ) << _fltMantissaBitCount;174const INT32 _fltMantissaMask = _fltHiddenBit - 1;175const INT32 _fltExponentMask = ((INT32( 1 ) << _fltExponentBitCount) - 1) << _fltMantissaBitCount;176const INT32 _fltSignBit = INT32( 1 ) << (_fltExponentBitCount + _fltMantissaBitCount);177178// ------------------------------------------------------------------------179// define min and max values as floats (clamp to these bounds)180// ------------------------------------------------------------------------181INT32 _fxpMaxPosValueFloat;182INT32 _fxpMaxNegValueFloat;183184if (c_bSigned)185{186// The maximum positive fixed point value is 2^(i-1) - 2^(-f).187// The following constructs the floating point bit pattern for this value,188// as long as i >= 2.189_fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits - 1) <<_fltMantissaBitCount;190const INT32 iShift = _fltMantissaBitCount + 2 - c_uIBits - c_uFBits;191if (iShift >= 0)192{193// assert( iShift < 32 );194#if defined(_MSC_VER)195#pragma warning( push )196#pragma warning( disable : 4293 26452 )197#endif198_fxpMaxPosValueFloat -= INT32( 1 ) << iShift;199#if defined(_MSC_VER)200#pragma warning( pop )201#endif202}203204// The maximum negative fixed point value is -2^(i-1).205// The following constructs the floating point bit pattern for this value,206// as long as i >= 2.207// We need this number without the sign bit208_fxpMaxNegValueFloat = (_fltExponentBias + c_uIBits - 1) << _fltMantissaBitCount;209}210else211{212// The maximum positive fixed point value is 2^(i) - 2^(-f).213// The following constructs the floating point bit pattern for this value,214// as long as i >= 2.215_fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits) <<_fltMantissaBitCount;216const INT32 iShift = _fltMantissaBitCount + 1 - c_uIBits - c_uFBits;217if (iShift >= 0)218{219// assert( iShift < 32 );220#if defined(_MSC_VER)221#pragma warning( push )222#pragma warning( disable : 4293 26452 )223#endif224_fxpMaxPosValueFloat -= INT32( 1 ) << iShift;225#if defined(_MSC_VER)226#pragma warning( pop )227#endif228}229230// The maximum negative fixed point value is 0.231_fxpMaxNegValueFloat = 0;232}233234// ------------------------------------------------------------------------235// float -> fixed conversion236// ------------------------------------------------------------------------237238// ------------------------------------------------------------------------239// examine input float240// ------------------------------------------------------------------------241INT32 output = *(INT32*)&input;242INT32 unbiasedExponent = ((output & _fltExponentMask) >> _fltMantissaBitCount) - _fltExponentBias;243INT32 isNegative = output & _fltSignBit;244245// ------------------------------------------------------------------------246// nan247// ------------------------------------------------------------------------248if (unbiasedExponent == (_fltExponentBias + 1) && (output & _fltMantissaMask))249{250// nan converts to 0251output = 0;252}253// ------------------------------------------------------------------------254// too large positive255// ------------------------------------------------------------------------256else if (!isNegative && output >= _fxpMaxPosValueFloat) // integer compare257{258output = c_iMaxResult;259}260// ------------------------------------------------------------------------261// too large negative262// ------------------------------------------------------------------------263// integer compare264else if (isNegative && (output & ~_fltSignBit) >= _fxpMaxNegValueFloat)265{266output = c_iMinResult;267}268// ------------------------------------------------------------------------269// too small270// ------------------------------------------------------------------------271else if (unbiasedExponent < -c_uFBits - 1)272{273// clamp to 0274output = 0;275}276// ------------------------------------------------------------------------277// within range278// ------------------------------------------------------------------------279else280{281// copy mantissa, add hidden bit282output = (output & _fltMantissaMask) | _fltHiddenBit;283284INT32 extraBits = _fltMantissaBitCount - c_uFBits - unbiasedExponent;285if (extraBits >= 0)286{287// 2's complement if negative288if (isNegative)289{290output = ~output + 1;291}292293// From the range checks that led here, it is known that294// unbiasedExponent < c_uIBits. So, at most:295// (a) unbiasedExponent == c_uIBits - 1.296//297// From compile validation above, it is known that298// c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).299// So, at minimum:300// (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1301//302// Substituting (a) and (b) into extraBits calculation above:303// extraBits >= (_fxtIntBitCount + c_uFBits - 1)304// - c_uFBits - (c_uIBits - 1)305// extraBits >= 0306//307// Thus we only have to worry about shifting right by 0 or more308// bits to get the decimal to the right place, and never have309// to shift left.310311INT32 LSB = 1 << extraBits; // last bit being kept312INT32 extraBitsMask = LSB - 1;313INT32 half = LSB >> 1; // round bias314315// round to nearest-even at LSB316if ((output & LSB) || (output & extraBitsMask) > half)317{318output += half;319}320321// shift off the extra bits (sign extending)322output >>= extraBits;323}324else325{326output <<= -extraBits;327328// 2's complement if negative329if (isNegative)330{331output = ~output + 1;332}333}334}335return output;336}337//-----------------------------------------------------------------------------------------------------------------------------338339#define FXP_INTEGER_BITS 15340#define FXP_FRACTION_BITS 16341#define FXP_FRACTION_MASK 0x0000ffff342#define FXP_INTEGER_MASK 0x7fff0000343#define FXP_THREE (3<<FXP_FRACTION_BITS)344#define FXP_ONE (1<<FXP_FRACTION_BITS)345#define FXP_ONE_THIRD 0x00005555346#define FXP_TWO_THIRDS 0x0000aaaa347#define FXP_ONE_HALF 0x00008000348349#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than350// or equal to this allows avg. reduction on a tri patch351// including rounding.352353#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than354// or equal to this allows avg. reduction on a quad patch355// including rounding.356357static const FXP s_fixedReciprocal[PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR+1] =358{3590xffffffff, // 1/0 is the first entry (unused)3600x10000, 0x8000, 0x5555, 0x4000,3610x3333, 0x2aab, 0x2492, 0x2000,3620x1c72, 0x199a, 0x1746, 0x1555,3630x13b1, 0x1249, 0x1111, 0x1000,3640xf0f, 0xe39, 0xd79, 0xccd,3650xc31, 0xba3, 0xb21, 0xaab,3660xa3d, 0x9d9, 0x97b, 0x925,3670x8d4, 0x889, 0x842, 0x800,3680x7c2, 0x788, 0x750, 0x71c,3690x6eb, 0x6bd, 0x690, 0x666,3700x63e, 0x618, 0x5f4, 0x5d1,3710x5b0, 0x591, 0x572, 0x555,3720x539, 0x51f, 0x505, 0x4ec,3730x4d5, 0x4be, 0x4a8, 0x492,3740x47e, 0x46a, 0x457, 0x444,3750x432, 0x421, 0x410, 0x400, // 1/64 is the last entry376};377378#define FLOAT_THREE 3.0f379#define FLOAT_ONE 1.0f380381//---------------------------------------------------------------------------------------------------------------------------------382// floatToFixed383//---------------------------------------------------------------------------------------------------------------------------------384FXP floatToFixed(const float& input)385{386return floatToIDotF< FXP_INTEGER_BITS, FXP_FRACTION_BITS, /*bSigned*/false >( input );387}388389//---------------------------------------------------------------------------------------------------------------------------------390// fixedToFloat391//---------------------------------------------------------------------------------------------------------------------------------392float fixedToFloat(const FXP& input)393{394// not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.395return ((float)(input>>FXP_FRACTION_BITS) + (float)(input&FXP_FRACTION_MASK)/(1<<FXP_FRACTION_BITS));396}397398//---------------------------------------------------------------------------------------------------------------------------------399// isEven400//---------------------------------------------------------------------------------------------------------------------------------401bool isEven(const float& input)402{403return (((int)input) & 1) ? false : true;404}405406//---------------------------------------------------------------------------------------------------------------------------------407// fxpCeil408//---------------------------------------------------------------------------------------------------------------------------------409FXP fxpCeil(const FXP& input)410{411if( input & FXP_FRACTION_MASK )412{413return (input & FXP_INTEGER_MASK) + FXP_ONE;414}415return input;416}417418//---------------------------------------------------------------------------------------------------------------------------------419// fxpFloor420//---------------------------------------------------------------------------------------------------------------------------------421FXP fxpFloor(const FXP& input)422{423return (input & FXP_INTEGER_MASK);424}425426//=================================================================================================================================427// CHWTessellator428//=================================================================================================================================429430//---------------------------------------------------------------------------------------------------------------------------------431// CHWTessellator::CHWTessellator432//---------------------------------------------------------------------------------------------------------------------------------433CHWTessellator::CHWTessellator()434{435m_Point = 0;436m_Index = 0;437m_NumPoints = 0;438m_NumIndices = 0;439m_bUsingPatchedIndices = false;440m_bUsingPatchedIndices2 = false;441}442//---------------------------------------------------------------------------------------------------------------------------------443// CHWTessellator::~CHWTessellator444//---------------------------------------------------------------------------------------------------------------------------------445CHWTessellator::~CHWTessellator()446{447delete [] m_Point;448delete [] m_Index;449}450451//---------------------------------------------------------------------------------------------------------------------------------452// CHWTessellator::Init453// User calls this.454//---------------------------------------------------------------------------------------------------------------------------------455void CHWTessellator::Init(456PIPE_TESSELLATOR_PARTITIONING partitioning,457PIPE_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive)458{459if( 0 == m_Point )460{461m_Point = new DOMAIN_POINT[MAX_POINT_COUNT];462}463if( 0 == m_Index )464{465m_Index = new int[MAX_INDEX_COUNT];466}467m_partitioning = partitioning;468m_originalPartitioning = partitioning;469switch( partitioning )470{471case PIPE_TESSELLATOR_PARTITIONING_INTEGER:472default:473break;474case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:475m_parity = TESSELLATOR_PARITY_ODD;476break;477case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:478m_parity = TESSELLATOR_PARITY_EVEN;479break;480}481m_originalParity = m_parity;482m_outputPrimitive = outputPrimitive;483m_NumPoints = 0;484m_NumIndices = 0;485}486//---------------------------------------------------------------------------------------------------------------------------------487// CHWTessellator::TessellateQuadDomain488// User calls this489//---------------------------------------------------------------------------------------------------------------------------------490void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,491float insideTessFactor_U, float insideTessFactor_V )492{493PROCESSED_TESS_FACTORS_QUAD processedTessFactors;494QuadProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactor_U,insideTessFactor_V,processedTessFactors);495496if( processedTessFactors.bPatchCulled )497{498m_NumPoints = 0;499m_NumIndices = 0;500return;501}502else if( processedTessFactors.bJustDoMinimumTessFactor )503{504DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);505DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/1);506DefinePoint(/*U*/FXP_ONE,/*V*/FXP_ONE,/*pointStorageOffset*/2);507DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/3);508m_NumPoints = 4;509510switch(m_outputPrimitive)511{512case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:513case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:514// function orients them CCW if needed515DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);516DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);517m_NumIndices = 6;518break;519case PIPE_TESSELLATOR_OUTPUT_POINT:520DumpAllPoints();521break;522case PIPE_TESSELLATOR_OUTPUT_LINE:523DumpAllPointsAsInOrderLineList();524break;525}526return;527}528529QuadGeneratePoints(processedTessFactors);530531if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )532{533DumpAllPoints();534return;535}536if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )537{538DumpAllPointsAsInOrderLineList();539return;540}541542QuadGenerateConnectivity(processedTessFactors); // can be done in parallel to QuadGeneratePoints()543}544545//---------------------------------------------------------------------------------------------------------------------------------546// CHWTessellator::QuadProcessTessFactors547//---------------------------------------------------------------------------------------------------------------------------------548void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,549float insideTessFactor_U, float insideTessFactor_V, PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )550{551// Is the patch culled?552if( !(tessFactor_Ueq0 > 0) || // NaN will pass553!(tessFactor_Veq0 > 0) ||554!(tessFactor_Ueq1 > 0) ||555!(tessFactor_Veq1 > 0) )556{557processedTessFactors.bPatchCulled = true;558return;559}560else561{562processedTessFactors.bPatchCulled = false;563}564565// Clamp edge TessFactors566float lowerBound = 0.0, upperBound = 0.0;567switch(m_originalPartitioning)568{569case PIPE_TESSELLATOR_PARTITIONING_INTEGER:570case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer571lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;572upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;573break;574575case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:576lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;577upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;578break;579580case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:581lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;582upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;583break;584}585586tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );587tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );588tessFactor_Ueq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq1 ) );589tessFactor_Veq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq1 ) );590591if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)592{593tessFactor_Ueq0 = ceil(tessFactor_Ueq0);594tessFactor_Veq0 = ceil(tessFactor_Veq0);595tessFactor_Ueq1 = ceil(tessFactor_Ueq1);596tessFactor_Veq1 = ceil(tessFactor_Veq1);597}598599// Clamp inside TessFactors600if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)601{602#define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction603#define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)604// If any TessFactor will end up > 1 after floatToFixed conversion later,605// then force the inside TessFactors to be > 1 so there is a picture frame.606if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||607(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||608(tessFactor_Ueq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||609(tessFactor_Veq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||610(insideTessFactor_U > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||611(insideTessFactor_V > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) )612{613// Force picture frame614lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;615}616}617618insideTessFactor_U = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_U ) );619insideTessFactor_V = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_V ) );620// Note the above clamps map NaN to lowerBound621622623if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)624{625insideTessFactor_U = ceil(insideTessFactor_U);626insideTessFactor_V = ceil(insideTessFactor_V);627}628629// Reset our vertex and index buffers. We have enough storage for the max tessFactor.630m_NumPoints = 0;631m_NumIndices = 0;632633// Process tessFactors634float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};635float insideTessFactor[QUAD_AXES] = {insideTessFactor_U,insideTessFactor_V};636int edge, axis;637if( HWIntegerPartitioning() )638{639for( edge = 0; edge < QUAD_EDGES; edge++ )640{641int edgeEven = isEven(outsideTessFactor[edge]);642processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;643}644for( axis = 0; axis < QUAD_AXES; axis++ )645{646processedTessFactors.insideTessFactorParity[axis] =647(isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )648? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;649}650}651else652{653for( edge = 0; edge < QUAD_EDGES; edge++ )654{655processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;656}657processedTessFactors.insideTessFactorParity[U] = processedTessFactors.insideTessFactorParity[V] = m_originalParity;658}659660// Save fixed point TessFactors661for( edge = 0; edge < QUAD_EDGES; edge++ )662{663processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);664}665for( axis = 0; axis < QUAD_AXES; axis++ )666{667processedTessFactors.insideTessFactor[axis] = floatToFixed(insideTessFactor[axis]);668}669670if( HWIntegerPartitioning() || Odd() )671{672// Special case if all TessFactors are 1673if( (FXP_ONE == processedTessFactors.insideTessFactor[U]) &&674(FXP_ONE == processedTessFactors.insideTessFactor[V]) &&675(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&676(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&677(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq1]) &&678(FXP_ONE == processedTessFactors.outsideTessFactor[Veq1]) )679{680processedTessFactors.bJustDoMinimumTessFactor = true;681return;682}683}684processedTessFactors.bJustDoMinimumTessFactor = false;685686// Compute TessFactor-specific metadata687for(int edge = 0; edge < QUAD_EDGES; edge++ )688{689SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);690ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);691}692693for(int axis = 0; axis < QUAD_AXES; axis++)694{695SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);696ComputeTessFactorContext(processedTessFactors.insideTessFactor[axis], processedTessFactors.insideTessFactorCtx[axis]);697}698699// Compute some initial data.700701// outside edge offsets and storage702for(int edge = 0; edge < QUAD_EDGES; edge++ )703{704SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);705processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);706m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];707}708m_NumPoints -= 4;709710// inside edge offsets711for(int axis = 0; axis < QUAD_AXES; axis++)712{713SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);714processedTessFactors.numPointsForInsideTessFactor[axis] = NumPointsForTessFactor(processedTessFactors.insideTessFactor[axis]);715int pointCountMin = ( TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[axis] ) ? 4 : 3;716// max() allows degenerate transition regions when inside TessFactor == 1717processedTessFactors.numPointsForInsideTessFactor[axis] = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor[axis]);718}719720processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;721722// inside storage, including interior edges above723int numInteriorPoints = (processedTessFactors.numPointsForInsideTessFactor[U] - 2)*(processedTessFactors.numPointsForInsideTessFactor[V]-2);724m_NumPoints += numInteriorPoints;725}726727//---------------------------------------------------------------------------------------------------------------------------------728// CHWTessellator::QuadGeneratePoints729//---------------------------------------------------------------------------------------------------------------------------------730void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )731{732// Generate exterior ring edge points, clockwise from top-left733int pointOffset = 0;734int edge;735for(edge = 0; edge < QUAD_EDGES; edge++ )736{737int parity = edge&0x1;738int startPoint = 0;739int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;740for(int p = startPoint; p < endPoint; p++,pointOffset++) // don't include end, since next edge starts with it.741{742FXP fxpParam;743int q = ((edge==1)||(edge==2)) ? p : endPoint - p; // reverse order744SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);745PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);746if( parity )747{748DefinePoint(/*U*/fxpParam,749/*V*/(edge == 3) ? FXP_ONE : 0,750/*pointStorageOffset*/pointOffset);751}752else753{754DefinePoint(/*U*/(edge == 2) ? FXP_ONE : 0,755/*V*/fxpParam,756/*pointStorageOffset*/pointOffset);757}758}759}760761// Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center762static const int startRing = 1;763int minNumPointsForTessFactor = min(processedTessFactors.numPointsForInsideTessFactor[U],processedTessFactors.numPointsForInsideTessFactor[V]);764int numRings = (minNumPointsForTessFactor >> 1); // note for even tess we aren't counting center point here.765for(int ring = startRing; ring < numRings; ring++)766{767int startPoint = ring;768int endPoint[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint,769processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint};770771for(edge = 0; edge < QUAD_EDGES; edge++ )772{773int parity[QUAD_AXES] = {edge&0x1,((edge+1)&0x1)};774int perpendicularAxisPoint = (edge < 2) ? startPoint : endPoint[parity[0]];775FXP fxpPerpParam;776SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[0]]);777PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[0]],perpendicularAxisPoint,fxpPerpParam);778SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[1]]);779for(int p = startPoint; p < endPoint[parity[1]]; p++, pointOffset++) // don't include end: next edge starts with it.780{781FXP fxpParam;782int q = ((edge == 1)||(edge==2)) ? p : endPoint[parity[1]] - (p - startPoint);783PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[1]],q,fxpParam);784if( parity[1] )785{786DefinePoint(/*U*/fxpPerpParam,787/*V*/fxpParam,788/*pointStorageOffset*/pointOffset);789}790else791{792DefinePoint(/*U*/fxpParam,793/*V*/fxpPerpParam,794/*pointStorageOffset*/pointOffset);795}796}797}798}799// For even tessellation, the inner "ring" is degenerate - a row of points800if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&801(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) )802{803int startPoint = numRings;804int endPoint = processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint;805SetTessellationParity(processedTessFactors.insideTessFactorParity[U]);806for( int p = startPoint; p <= endPoint; p++, pointOffset++ )807{808FXP fxpParam;809PlacePointIn1D(processedTessFactors.insideTessFactorCtx[U],p,fxpParam);810DefinePoint(/*U*/fxpParam,811/*V*/FXP_ONE_HALF, // middle812/*pointStorageOffset*/pointOffset);813}814}815else if( (processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&816(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) )817{818int startPoint = numRings;819int endPoint;820FXP fxpParam;821endPoint = processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint;822SetTessellationParity(processedTessFactors.insideTessFactorParity[V]);823for( int p = endPoint; p >= startPoint; p--, pointOffset++ )824{825PlacePointIn1D(processedTessFactors.insideTessFactorCtx[V],p,fxpParam);826DefinePoint(/*U*/FXP_ONE_HALF, // middle827/*V*/fxpParam,828/*pointStorageOffset*/pointOffset);829}830}831}832//---------------------------------------------------------------------------------------------------------------------------------833// CHWTessellator::QuadGenerateConnectivity834//---------------------------------------------------------------------------------------------------------------------------------835void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )836{837// Generate primitives for all the concentric rings, one side at a time for each ring838static const int startRing = 1;839int numPointRowsToCenter[QUAD_AXES] = {((processedTessFactors.numPointsForInsideTessFactor[U]+1) >> 1),840((processedTessFactors.numPointsForInsideTessFactor[V]+1) >> 1)}; // +1 is so even tess includes the center point841int numRings = min(numPointRowsToCenter[U],numPointRowsToCenter[V]);842int degeneratePointRing[QUAD_AXES] = { // Even partitioning causes degenerate row of points,843// which results in exceptions to the point ordering conventions844// when travelling around the rings counterclockwise.845(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ? numPointRowsToCenter[V] - 1 : -1,846(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) ? numPointRowsToCenter[U] - 1 : -1 };847848const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[QUAD_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],849&processedTessFactors.outsideTessFactorCtx[Veq0],850&processedTessFactors.outsideTessFactorCtx[Ueq1],851&processedTessFactors.outsideTessFactorCtx[Veq1]};852TESSELLATOR_PARITY outsideTessFactorParity[QUAD_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],853processedTessFactors.outsideTessFactorParity[Veq0],854processedTessFactors.outsideTessFactorParity[Ueq1],855processedTessFactors.outsideTessFactorParity[Veq1]};856int numPointsForOutsideEdge[QUAD_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],857processedTessFactors.numPointsForOutsideEdge[Veq0],858processedTessFactors.numPointsForOutsideEdge[Ueq1],859processedTessFactors.numPointsForOutsideEdge[Veq1]};860861int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;862int outsideEdgePointBaseOffset = 0;863int edge;864for(int ring = startRing; ring < numRings; ring++)865{866int numPointsForInsideEdge[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 2*ring,867processedTessFactors.numPointsForInsideTessFactor[V] - 2*ring};868869int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;870int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;871872for(edge = 0; edge < QUAD_EDGES; edge++ )873{874int parity = (edge+1)&0x1;875876int numTriangles = numPointsForInsideEdge[parity] + numPointsForOutsideEdge[edge] - 2;877int insideBaseOffset;878int outsideBaseOffset;879if( edge == 3 ) // We need to patch the indexing so Stitch() can think it sees880// 2 sequentially increasing rows of points, even though we have wrapped around881// to the end of the inner and outer ring's points, so the last point is really882// the first point for the ring.883// We make it so that when Stitch() calls AddIndex(), that function884// will do any necessary index adjustment.885{886if( ring == degeneratePointRing[parity] )887{888m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset + 1;889m_IndexPatchContext2.cornerCaseBadValue = outsideEdgePointBaseOffset + numPointsForOutsideEdge[edge] - 1;890m_IndexPatchContext2.cornerCaseReplacementValue = edge0OutsidePointBaseOffset;891m_IndexPatchContext2.indexInversionEndPoint = (m_IndexPatchContext2.baseIndexToInvert << 1) - 1;892insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;893outsideBaseOffset = outsideEdgePointBaseOffset;894SetUsingPatchedIndices2(true);895}896else897{898m_IndexPatchContext.insidePointIndexDeltaToRealValue = insideEdgePointBaseOffset;899m_IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge[parity] - 1;900m_IndexPatchContext.insidePointIndexReplacementValue = edge0InsidePointBaseOffset;901m_IndexPatchContext.outsidePointIndexPatchBase = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range902m_IndexPatchContext.outsidePointIndexDeltaToRealValue = outsideEdgePointBaseOffset903- m_IndexPatchContext.outsidePointIndexPatchBase;904m_IndexPatchContext.outsidePointIndexBadValue = m_IndexPatchContext.outsidePointIndexPatchBase905+ numPointsForOutsideEdge[edge] - 1;906m_IndexPatchContext.outsidePointIndexReplacementValue = edge0OutsidePointBaseOffset;907908insideBaseOffset = 0;909outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;910SetUsingPatchedIndices(true);911}912}913else if( (edge == 2) && (ring == degeneratePointRing[parity]) )914{915m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset;916m_IndexPatchContext2.cornerCaseBadValue = -1; // unused917m_IndexPatchContext2.cornerCaseReplacementValue = -1; // unused918m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert << 1;919insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;920outsideBaseOffset = outsideEdgePointBaseOffset;921SetUsingPatchedIndices2(true);922}923else924{925insideBaseOffset = insideEdgePointBaseOffset;926outsideBaseOffset = outsideEdgePointBaseOffset;927}928if( ring == startRing )929{930StitchTransition(/*baseIndexOffset: */m_NumIndices,931insideBaseOffset,processedTessFactors.insideTessFactorCtx[parity].numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity[parity],932outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);933}934else935{936StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,937/*baseIndexOffset: */m_NumIndices,938numPointsForInsideEdge[parity],939insideBaseOffset,outsideBaseOffset);940}941SetUsingPatchedIndices(false);942SetUsingPatchedIndices2(false);943m_NumIndices += numTriangles*3;944outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;945if( (edge == 2) && (ring == degeneratePointRing[parity]) )946{947insideEdgePointBaseOffset -= numPointsForInsideEdge[parity] - 1;948}949else950{951insideEdgePointBaseOffset += numPointsForInsideEdge[parity] - 1;952}953numPointsForOutsideEdge[edge] = numPointsForInsideEdge[parity];954}955if( startRing == ring )956{957for(edge = 0; edge < QUAD_EDGES; edge++ )958{959outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx[edge&1];960outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity[edge&1];961}962}963}964965// Triangulate center - a row of quads if odd966// This triangulation may be producing diagonals that are asymmetric about967// the center of the patch in this region.968if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&969(TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[V] ) )970{971SetUsingPatchedIndices2(true);972int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[U]>>1) - (processedTessFactors.numPointsForInsideTessFactor[V]>>1))<<1)+973((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U] ) ? 2 : 1);974m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 2;975m_IndexPatchContext2.cornerCaseBadValue = m_IndexPatchContext2.baseIndexToInvert;976m_IndexPatchContext2.cornerCaseReplacementValue = outsideEdgePointBaseOffset;977m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +978m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;979StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE,980/*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,981/*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,982outsideEdgePointBaseOffset+1);983SetUsingPatchedIndices2(false);984m_NumIndices += stripNumQuads*6;985}986else if((processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&987(TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[U]) )988{989SetUsingPatchedIndices2(true);990int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[V]>>1) - (processedTessFactors.numPointsForInsideTessFactor[U]>>1))<<1)+991((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V] ) ? 2 : 1);992m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 1;993m_IndexPatchContext2.cornerCaseBadValue = -1; // unused994m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +995m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;996DIAGONALS diag = (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ?997DIAGONALS_INSIDE_TO_OUTSIDE : DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE;998StitchRegular(/*bTrapezoid*/false,diag,999/*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,1000/*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,1001outsideEdgePointBaseOffset);1002SetUsingPatchedIndices2(false);1003m_NumIndices += stripNumQuads*6;1004}1005}10061007//---------------------------------------------------------------------------------------------------------------------------------1008// CHWTessellator::TessellateTriDomain1009// User calls this1010//---------------------------------------------------------------------------------------------------------------------------------1011void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,1012float insideTessFactor )1013{1014PROCESSED_TESS_FACTORS_TRI processedTessFactors;1015TriProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactor,processedTessFactors);10161017if( processedTessFactors.bPatchCulled )1018{1019m_NumPoints = 0;1020m_NumIndices = 0;1021return;1022}1023else if( processedTessFactors.bJustDoMinimumTessFactor )1024{1025DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)1026DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)1027DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)1028m_NumPoints = 3;10291030switch(m_outputPrimitive)1031{1032case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:1033case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:1034// function orients them CCW if needed1035DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices);1036m_NumIndices = 3;1037break;1038case PIPE_TESSELLATOR_OUTPUT_POINT:1039DumpAllPoints();1040break;1041case PIPE_TESSELLATOR_OUTPUT_LINE:1042DumpAllPointsAsInOrderLineList();1043break;1044}1045return;1046}10471048TriGeneratePoints(processedTessFactors);10491050if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )1051{1052DumpAllPoints();1053return;1054}1055if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )1056{1057DumpAllPointsAsInOrderLineList();1058return;1059}10601061TriGenerateConnectivity(processedTessFactors); // can be done in parallel to TriGeneratePoints()1062}10631064//---------------------------------------------------------------------------------------------------------------------------------1065// CHWTessellator::TriProcessTessFactors1066//---------------------------------------------------------------------------------------------------------------------------------1067void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,1068float insideTessFactor, PROCESSED_TESS_FACTORS_TRI& processedTessFactors )1069{1070// Is the patch culled?1071if( !(tessFactor_Ueq0 > 0) || // NaN will pass1072!(tessFactor_Veq0 > 0) ||1073!(tessFactor_Weq0 > 0) )1074{1075processedTessFactors.bPatchCulled = true;1076return;1077}1078else1079{1080processedTessFactors.bPatchCulled = false;1081}10821083// Clamp edge TessFactors1084float lowerBound = 0.0, upperBound = 0.0;1085switch(m_originalPartitioning)1086{1087case PIPE_TESSELLATOR_PARTITIONING_INTEGER:1088case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer1089lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;1090upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;1091break;10921093case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:1094lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;1095upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;1096break;10971098case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:1099lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;1100upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;1101break;1102}11031104tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );1105tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );1106tessFactor_Weq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Weq0 ) );11071108if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)1109{1110tessFactor_Ueq0 = ceil(tessFactor_Ueq0);1111tessFactor_Veq0 = ceil(tessFactor_Veq0);1112tessFactor_Weq0 = ceil(tessFactor_Weq0);1113}11141115// Clamp inside TessFactors1116if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)1117{1118if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||1119(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||1120(tessFactor_Weq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON))1121// Don't need the same check for insideTessFactor for tri patches,1122// since there is only one insideTessFactor, as opposed to quad1123// patches which have 2 insideTessFactors.1124{1125// Force picture frame1126lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;1127}1128}11291130insideTessFactor = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor ) );1131// Note the above clamps map NaN to lowerBound11321133if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)1134{1135insideTessFactor = ceil(insideTessFactor);1136}11371138// Reset our vertex and index buffers. We have enough storage for the max tessFactor.1139m_NumPoints = 0;1140m_NumIndices = 0;11411142// Process tessFactors1143float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};1144int edge;1145if( HWIntegerPartitioning() )1146{1147for( edge = 0; edge < TRI_EDGES; edge++ )1148{1149int edgeEven = isEven(outsideTessFactor[edge]);1150processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;1151}1152processedTessFactors.insideTessFactorParity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))1153? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;1154}1155else1156{1157for( edge = 0; edge < TRI_EDGES; edge++ )1158{1159processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;1160}1161processedTessFactors.insideTessFactorParity = m_originalParity;1162}11631164// Save fixed point TessFactors1165for( edge = 0; edge < TRI_EDGES; edge++ )1166{1167processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);1168}1169processedTessFactors.insideTessFactor = floatToFixed(insideTessFactor);11701171if( HWIntegerPartitioning() || Odd() )1172{1173// Special case if all TessFactors are 11174if( (FXP_ONE == processedTessFactors.insideTessFactor) &&1175(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&1176(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&1177(FXP_ONE == processedTessFactors.outsideTessFactor[Weq0]) )1178{1179processedTessFactors.bJustDoMinimumTessFactor = true;1180return;1181}1182}1183processedTessFactors.bJustDoMinimumTessFactor = false;11841185// Compute per-TessFactor metadata1186for(edge = 0; edge < TRI_EDGES; edge++ )1187{1188SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);1189ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);1190}1191SetTessellationParity(processedTessFactors.insideTessFactorParity);1192ComputeTessFactorContext(processedTessFactors.insideTessFactor, processedTessFactors.insideTessFactorCtx);11931194// Compute some initial data.11951196// outside edge offsets and storage1197for(edge = 0; edge < TRI_EDGES; edge++ )1198{1199SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);1200processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);1201m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];1202}1203m_NumPoints -= 3;12041205// inside edge offsets1206SetTessellationParity(processedTessFactors.insideTessFactorParity);1207processedTessFactors.numPointsForInsideTessFactor = NumPointsForTessFactor(processedTessFactors.insideTessFactor);1208{1209int pointCountMin = Odd() ? 4 : 3;1210// max() allows degenerate transition regions when inside TessFactor == 11211processedTessFactors.numPointsForInsideTessFactor = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor);1212}12131214processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;12151216// inside storage, including interior edges above1217{1218int numInteriorRings = (processedTessFactors.numPointsForInsideTessFactor >> 1) - 1;1219int numInteriorPoints;1220if( Odd() )1221{1222numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1) - numInteriorRings);1223}1224else1225{1226numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1)) + 1;1227}1228m_NumPoints += numInteriorPoints;1229}12301231}12321233//---------------------------------------------------------------------------------------------------------------------------------1234// CHWTessellator::TriGeneratePoints1235//---------------------------------------------------------------------------------------------------------------------------------1236void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )1237{1238// Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)1239int pointOffset = 0;1240int edge;1241for(edge = 0; edge < TRI_EDGES; edge++ )1242{1243int parity = edge&0x1;1244int startPoint = 0;1245int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;1246for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end, since next edge starts with it.1247{1248FXP fxpParam;1249int q = (parity) ? p : endPoint - p; // whether to reverse point order given we are defining V or U (W implicit):1250// edge0, VW, has V decreasing, so reverse 1D points below1251// edge1, WU, has U increasing, so don't reverse 1D points below1252// edge2, UV, has U decreasing, so reverse 1D points below1253SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);1254PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);1255if( edge == 0 )1256{1257DefinePoint(/*U*/0,1258/*V*/fxpParam,1259/*pointStorageOffset*/pointOffset);1260}1261else1262{1263DefinePoint(/*U*/fxpParam,1264/*V*/(edge == 2) ? FXP_ONE - fxpParam : 0,1265/*pointStorageOffset*/pointOffset);1266}1267}1268}12691270// Generate interior ring points, clockwise spiralling in1271SetTessellationParity(processedTessFactors.insideTessFactorParity);1272static const int startRing = 1;1273int numRings = (processedTessFactors.numPointsForInsideTessFactor >> 1);1274for(int ring = startRing; ring < numRings; ring++)1275{1276int startPoint = ring;1277int endPoint = processedTessFactors.numPointsForInsideTessFactor - 1 - startPoint;12781279for(edge = 0; edge < TRI_EDGES; edge++ )1280{1281int parity = edge&0x1;1282int perpendicularAxisPoint = startPoint;1283FXP fxpPerpParam;1284PlacePointIn1D(processedTessFactors.insideTessFactorCtx,perpendicularAxisPoint,fxpPerpParam);1285fxpPerpParam *= FXP_TWO_THIRDS; // Map location to the right size in barycentric space.1286// I (amarp) can draw a picture to explain.1287// We know this fixed point math won't over/underflow1288fxpPerpParam = (fxpPerpParam+FXP_ONE_HALF/*round*/)>>FXP_FRACTION_BITS; // get back to n.161289for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end: next edge starts with it.1290{1291FXP fxpParam;1292int q = (parity) ? p : endPoint - (p - startPoint); // whether to reverse point given we are defining V or U (W implicit):1293// edge0, VW, has V decreasing, so reverse 1D points below1294// edge1, WU, has U increasing, so don't reverse 1D points below1295// edge2, UV, has U decreasing, so reverse 1D points below1296PlacePointIn1D(processedTessFactors.insideTessFactorCtx,q,fxpParam);1297// edge0 VW, has perpendicular parameter U constant1298// edge1 WU, has perpendicular parameter V constant1299// edge2 UV, has perpendicular parameter W constant1300const unsigned int deriv = 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle1301switch(edge)1302{1303case 0:1304DefinePoint(/*U*/fxpPerpParam,1305/*V*/fxpParam - (fxpPerpParam+1/*round*/)/deriv, // we know this fixed point math won't over/underflow1306/*pointStorageOffset*/pointOffset);1307break;1308case 1:1309DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow1310/*V*/fxpPerpParam,1311/*pointStorageOffset*/pointOffset);1312break;1313case 2:1314DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow1315/*V*/FXP_ONE - (fxpParam - (fxpPerpParam+1/*round*/)/deriv) - fxpPerpParam,// we know this fixed point math won't over/underflow1316/*pointStorageOffset*/pointOffset);1317break;1318}1319}1320}1321}1322if( !Odd() )1323{1324// Last point is the point at the center.1325DefinePoint(/*U*/FXP_ONE_THIRD,1326/*V*/FXP_ONE_THIRD,1327/*pointStorageOffset*/pointOffset);1328}1329}1330//---------------------------------------------------------------------------------------------------------------------------------1331// CHWTessellator::TriGenerateConnectivity1332//---------------------------------------------------------------------------------------------------------------------------------1333void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )1334{1335// Generate primitives for all the concentric rings, one side at a time for each ring1336static const int startRing = 1;1337int numRings = ((processedTessFactors.numPointsForInsideTessFactor+1) >> 1); // +1 is so even tess includes the center point, which we want to now1338const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[TRI_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],1339&processedTessFactors.outsideTessFactorCtx[Veq0],1340&processedTessFactors.outsideTessFactorCtx[Weq0]};1341TESSELLATOR_PARITY outsideTessFactorParity[TRI_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],1342processedTessFactors.outsideTessFactorParity[Veq0],1343processedTessFactors.outsideTessFactorParity[Weq0]};1344int numPointsForOutsideEdge[TRI_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],1345processedTessFactors.numPointsForOutsideEdge[Veq0],1346processedTessFactors.numPointsForOutsideEdge[Weq0]};13471348int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;1349int outsideEdgePointBaseOffset = 0;1350int edge;1351for(int ring = startRing; ring < numRings; ring++)1352{1353int numPointsForInsideEdge = processedTessFactors.numPointsForInsideTessFactor - 2*ring;1354int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;1355int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;1356for(edge = 0; edge < TRI_EDGES; edge++ )1357{1358int numTriangles = numPointsForInsideEdge + numPointsForOutsideEdge[edge] - 2;13591360int insideBaseOffset;1361int outsideBaseOffset;1362if( edge == 2 )1363{1364m_IndexPatchContext.insidePointIndexDeltaToRealValue = insideEdgePointBaseOffset;1365m_IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge - 1;1366m_IndexPatchContext.insidePointIndexReplacementValue = edge0InsidePointBaseOffset;1367m_IndexPatchContext.outsidePointIndexPatchBase = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range1368m_IndexPatchContext.outsidePointIndexDeltaToRealValue = outsideEdgePointBaseOffset1369- m_IndexPatchContext.outsidePointIndexPatchBase;1370m_IndexPatchContext.outsidePointIndexBadValue = m_IndexPatchContext.outsidePointIndexPatchBase1371+ numPointsForOutsideEdge[edge] - 1;1372m_IndexPatchContext.outsidePointIndexReplacementValue = edge0OutsidePointBaseOffset;1373SetUsingPatchedIndices(true);1374insideBaseOffset = 0;1375outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;1376}1377else1378{1379insideBaseOffset = insideEdgePointBaseOffset;1380outsideBaseOffset = outsideEdgePointBaseOffset;1381}1382if( ring == startRing )1383{1384StitchTransition(/*baseIndexOffset: */m_NumIndices,1385insideBaseOffset,processedTessFactors.insideTessFactorCtx.numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity,1386outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);1387}1388else1389{1390StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,1391/*baseIndexOffset: */m_NumIndices,1392numPointsForInsideEdge,1393insideBaseOffset,outsideBaseOffset);1394}1395if( 2 == edge )1396{1397SetUsingPatchedIndices(false);1398}1399m_NumIndices += numTriangles*3;1400outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;1401insideEdgePointBaseOffset += numPointsForInsideEdge - 1;1402numPointsForOutsideEdge[edge] = numPointsForInsideEdge;1403}1404if( startRing == ring )1405{1406for(edge = 0; edge < TRI_EDGES; edge++ )1407{1408outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx;1409outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity;1410}1411}1412}1413if( Odd() )1414{1415// Triangulate center (a single triangle)1416DefineClockwiseTriangle(outsideEdgePointBaseOffset, outsideEdgePointBaseOffset+1, outsideEdgePointBaseOffset+2,1417m_NumIndices);1418m_NumIndices += 3;1419}1420}14211422//---------------------------------------------------------------------------------------------------------------------------------1423// CHWTessellator::TessellateIsoLineDomain1424// User calls this.1425//---------------------------------------------------------------------------------------------------------------------------------1426void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )1427{1428PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors;1429IsoLineProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail,processedTessFactors);1430if( processedTessFactors.bPatchCulled )1431{1432m_NumPoints = 0;1433m_NumIndices = 0;1434return;1435}1436IsoLineGeneratePoints(processedTessFactors);1437IsoLineGenerateConnectivity(processedTessFactors); // can be done in parallel to IsoLineGeneratePoints1438}14391440//---------------------------------------------------------------------------------------------------------------------------------1441// CHWTessellator::IsoLineProcessTessFactors1442//---------------------------------------------------------------------------------------------------------------------------------1443void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail,1444PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )1445{1446// Is the patch culled?1447if( !(TessFactor_V_LineDensity > 0) || // NaN will pass1448!(TessFactor_U_LineDetail > 0) )1449{1450processedTessFactors.bPatchCulled = true;1451return;1452}1453else1454{1455processedTessFactors.bPatchCulled = false;1456}14571458// Clamp edge TessFactors1459float lowerBound = 0.0, upperBound = 0.0;1460switch(m_originalPartitioning)1461{1462case PIPE_TESSELLATOR_PARTITIONING_INTEGER:1463case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer1464lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;1465upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;1466break;14671468case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:1469lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;1470upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;1471break;14721473case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:1474lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;1475upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;1476break;1477}14781479TessFactor_V_LineDensity = tess_fmin( PIPE_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR,1480tess_fmax( PIPE_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR, TessFactor_V_LineDensity ) );1481TessFactor_U_LineDetail = tess_fmin( upperBound, tess_fmax( lowerBound, TessFactor_U_LineDetail ) );14821483// Reset our vertex and index buffers. We have enough storage for the max tessFactor.1484m_NumPoints = 0;1485m_NumIndices = 0;14861487// Process tessFactors1488if( HWIntegerPartitioning() )1489{1490TessFactor_U_LineDetail = ceil(TessFactor_U_LineDetail);1491processedTessFactors.lineDetailParity = isEven(TessFactor_U_LineDetail) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;1492}1493else1494{1495processedTessFactors.lineDetailParity = m_originalParity;1496}14971498FXP fxpTessFactor_U_LineDetail = floatToFixed(TessFactor_U_LineDetail);14991500SetTessellationParity(processedTessFactors.lineDetailParity);15011502ComputeTessFactorContext(fxpTessFactor_U_LineDetail, processedTessFactors.lineDetailTessFactorCtx);1503processedTessFactors.numPointsPerLine = NumPointsForTessFactor(fxpTessFactor_U_LineDetail);15041505OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);15061507TessFactor_V_LineDensity = ceil(TessFactor_V_LineDensity);1508processedTessFactors.lineDensityParity = isEven(TessFactor_V_LineDensity) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;1509SetTessellationParity(processedTessFactors.lineDensityParity);1510FXP fxpTessFactor_V_LineDensity = floatToFixed(TessFactor_V_LineDensity);1511ComputeTessFactorContext(fxpTessFactor_V_LineDensity, processedTessFactors.lineDensityTessFactorCtx);15121513processedTessFactors.numLines = NumPointsForTessFactor(fxpTessFactor_V_LineDensity) - 1; // don't draw last line at V == 1.15141515RestorePartitioning();15161517// Compute some initial data.15181519// outside edge offsets1520m_NumPoints = processedTessFactors.numPointsPerLine * processedTessFactors.numLines;1521if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )1522{1523m_NumIndices = m_NumPoints;1524}1525else // line1526{1527m_NumIndices = processedTessFactors.numLines*(processedTessFactors.numPointsPerLine-1)*2;1528}1529}15301531//---------------------------------------------------------------------------------------------------------------------------------1532// CHWTessellator::IsoLineGeneratePoints1533//---------------------------------------------------------------------------------------------------------------------------------1534void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )1535{1536int line, pointOffset;1537for(line = 0, pointOffset = 0; line < processedTessFactors.numLines; line++)1538{1539for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)1540{1541FXP fxpU,fxpV;1542SetTessellationParity(processedTessFactors.lineDensityParity);1543PlacePointIn1D(processedTessFactors.lineDensityTessFactorCtx,line,fxpV);15441545SetTessellationParity(processedTessFactors.lineDetailParity);1546PlacePointIn1D(processedTessFactors.lineDetailTessFactorCtx,point,fxpU);15471548DefinePoint(fxpU,fxpV,pointOffset++);1549}1550}1551}15521553//---------------------------------------------------------------------------------------------------------------------------------1554// CHWTessellator::IsoLineGenerateConnectivity1555//---------------------------------------------------------------------------------------------------------------------------------1556void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )1557{1558int line, pointOffset, indexOffset;1559if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )1560{1561for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)1562{1563for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)1564{1565DefineIndex(pointOffset++,indexOffset++);1566}1567}1568}1569else // line1570{1571for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)1572{1573for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)1574{1575if( point > 0 )1576{1577DefineIndex(pointOffset-1,indexOffset++);1578DefineIndex(pointOffset,indexOffset++);1579}1580pointOffset++;1581}1582}1583}1584}15851586//---------------------------------------------------------------------------------------------------------------------------------1587// CHWTessellator::GetPointCount1588// User calls this.1589//---------------------------------------------------------------------------------------------------------------------------------1590int CHWTessellator::GetPointCount()1591{1592return m_NumPoints;1593}15941595//---------------------------------------------------------------------------------------------------------------------------------1596// CHWTessellator::GetIndexCount()1597// User calls this.1598//---------------------------------------------------------------------------------------------------------------------------------1599int CHWTessellator::GetIndexCount()1600{1601return m_NumIndices;1602}16031604//---------------------------------------------------------------------------------------------------------------------------------1605// CHWTessellator::GetPoints()1606// User calls this.1607//---------------------------------------------------------------------------------------------------------------------------------1608DOMAIN_POINT* CHWTessellator::GetPoints()1609{1610return m_Point;1611}1612//---------------------------------------------------------------------------------------------------------------------------------1613// CHWTessellator::GetIndices()1614// User calls this.1615//---------------------------------------------------------------------------------------------------------------------------------1616int* CHWTessellator::GetIndices()1617{1618return m_Index;1619}16201621//---------------------------------------------------------------------------------------------------------------------------------1622// CHWTessellator::DefinePoint()1623//---------------------------------------------------------------------------------------------------------------------------------1624int CHWTessellator::DefinePoint(FXP fxpU, FXP fxpV, int pointStorageOffset)1625{1626// WCHAR foo[80];1627// StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));1628// OutputDebugString(foo);1629m_Point[pointStorageOffset].u = fixedToFloat(fxpU);1630m_Point[pointStorageOffset].v = fixedToFloat(fxpV);1631return pointStorageOffset;1632}16331634//---------------------------------------------------------------------------------------------------------------------------------1635// CHWTessellator::DefineIndex()1636//--------------------------------------------------------------------------------------------------------------------------------1637void CHWTessellator::DefineIndex(int index, int indexStorageOffset)1638{1639index = PatchIndexValue(index);1640// WCHAR foo[80];1641// StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);1642// OutputDebugString(foo);1643m_Index[indexStorageOffset] = index;1644}16451646//---------------------------------------------------------------------------------------------------------------------------------1647// CHWTessellator::DefineClockwiseTriangle()1648//---------------------------------------------------------------------------------------------------------------------------------1649void CHWTessellator::DefineClockwiseTriangle(int index0, int index1, int index2, int indexStorageBaseOffset)1650{1651// inputs a clockwise triangle, stores a CW or CCW triangle depending on the state1652DefineIndex(index0,indexStorageBaseOffset);1653bool bWantClockwise = (m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW) ? true : false;1654if( bWantClockwise )1655{1656DefineIndex(index1,indexStorageBaseOffset+1);1657DefineIndex(index2,indexStorageBaseOffset+2);1658}1659else1660{1661DefineIndex(index2,indexStorageBaseOffset+1);1662DefineIndex(index1,indexStorageBaseOffset+2);1663}1664}16651666//---------------------------------------------------------------------------------------------------------------------------------1667// CHWTessellator::DumpAllPoints()1668//---------------------------------------------------------------------------------------------------------------------------------1669void CHWTessellator::DumpAllPoints()1670{1671for( int p = 0; p < m_NumPoints; p++ )1672{1673DefineIndex(p,m_NumIndices++);1674}1675}16761677//---------------------------------------------------------------------------------------------------------------------------------1678// CHWTessellator::DumpAllPointsAsInOrderLineList()1679//---------------------------------------------------------------------------------------------------------------------------------1680void CHWTessellator::DumpAllPointsAsInOrderLineList()1681{1682for( int p = 1; p < m_NumPoints; p++ )1683{1684DefineIndex(p-1,m_NumIndices++);1685DefineIndex(p,m_NumIndices++);1686}1687}16881689//---------------------------------------------------------------------------------------------------------------------------------1690// RemoveMSB1691//---------------------------------------------------------------------------------------------------------------------------------1692int RemoveMSB(int val)1693{1694int check;1695if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }1696else { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }1697for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return (val & ~check); }1698return 0;1699}1700//---------------------------------------------------------------------------------------------------------------------------------1701// GetMSB1702//---------------------------------------------------------------------------------------------------------------------------------1703int GetMSB(int val)1704{1705int check;1706if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }1707else { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }1708for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return check; }1709return 0;1710}17111712//---------------------------------------------------------------------------------------------------------------------------------1713// CHWTessellator::CleanseParameter()1714//---------------------------------------------------------------------------------------------------------------------------------1715/* NOTHING TO DO FOR FIXED POINT ARITHMETIC!1716void CHWTessellator::CleanseParameter(float& parameter)1717{1718// Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.1719parameter = 1.0f - parameter;1720parameter = 1.0f - parameter;17211722}1723*/1724//---------------------------------------------------------------------------------------------------------------------------------1725// CHWTessellator::NumPointsForTessFactor()1726//---------------------------------------------------------------------------------------------------------------------------------1727int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor )1728{1729int numPoints;1730if( Odd() )1731{1732numPoints = (fxpCeil(FXP_ONE_HALF + (fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS;1733}1734else1735{1736numPoints = ((fxpCeil((fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS)+1;1737}1738return numPoints;1739}17401741//---------------------------------------------------------------------------------------------------------------------------------1742// CHWTessellator::ComputeTessFactorContext()1743//---------------------------------------------------------------------------------------------------------------------------------1744void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor, TESS_FACTOR_CONTEXT& TessFactorCtx )1745{1746FXP fxpHalfTessFactor = (fxpTessFactor+1/*round*/)/2;1747if( Odd() || (fxpHalfTessFactor == FXP_ONE_HALF)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.1748{1749fxpHalfTessFactor += FXP_ONE_HALF;1750}1751FXP fxpFloorHalfTessFactor = fxpFloor(fxpHalfTessFactor);1752FXP fxpCeilHalfTessFactor = fxpCeil(fxpHalfTessFactor);1753TessFactorCtx.fxpHalfTessFactorFraction = fxpHalfTessFactor - fxpFloorHalfTessFactor;1754//CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);1755TessFactorCtx.numHalfTessFactorPoints = (fxpCeilHalfTessFactor>>FXP_FRACTION_BITS); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor1756if( fxpCeilHalfTessFactor == fxpFloorHalfTessFactor )1757{1758TessFactorCtx.splitPointOnFloorHalfTessFactor = /*pick value to cause this to be ignored*/ TessFactorCtx.numHalfTessFactorPoints+1;1759}1760else if( Odd() )1761{1762if( fxpFloorHalfTessFactor == FXP_ONE )1763{1764TessFactorCtx.splitPointOnFloorHalfTessFactor = 0;1765}1766else1767{1768TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB((fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)-1)<<1) + 1;1769}1770}1771else1772{1773TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB(fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)<<1) + 1;1774}1775int numFloorSegments = (fxpFloorHalfTessFactor * 2)>>FXP_FRACTION_BITS;1776int numCeilSegments = (fxpCeilHalfTessFactor * 2)>>FXP_FRACTION_BITS;1777if( Odd() )1778{1779numFloorSegments -= 1;1780numCeilSegments -= 1;1781}1782TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor = s_fixedReciprocal[numFloorSegments];1783TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor = s_fixedReciprocal[numCeilSegments];1784}17851786//---------------------------------------------------------------------------------------------------------------------------------1787// CHWTessellator::PlacePointIn1D()1788//---------------------------------------------------------------------------------------------------------------------------------1789void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT& TessFactorCtx, int point, FXP& fxpLocation )1790{1791bool bFlip;1792if( point >= TessFactorCtx.numHalfTessFactorPoints )1793{1794point = (TessFactorCtx.numHalfTessFactorPoints << 1) - point;1795if( Odd() )1796{1797point -= 1;1798}1799bFlip = true;1800}1801else1802{1803bFlip = false;1804}1805if( point == TessFactorCtx.numHalfTessFactorPoints )1806{1807fxpLocation = FXP_ONE_HALF; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly1808return;1809}1810unsigned int indexOnCeilHalfTessFactor = point;1811unsigned int indexOnFloorHalfTessFactor = indexOnCeilHalfTessFactor;1812if( point > TessFactorCtx.splitPointOnFloorHalfTessFactor )1813{1814indexOnFloorHalfTessFactor -= 1;1815}1816// For the fixed point multiplies below, we know the results are <= 16 bits because1817// the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.1818// So a number divided by a number that is at least twice as big will give1819// a result no bigger than 0.5 (which in fixed point is 16 bits in our case)1820FXP fxpLocationOnFloorHalfTessFactor = indexOnFloorHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor;1821FXP fxpLocationOnCeilHalfTessFactor = indexOnCeilHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor;18221823// Since we know the numbers calculated above are <= fixed point 0.5, and the equation1824// below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know1825// that the final result before shifting by 16 bits is no larger than 0x80000000. Once we1826// shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously1827// at most 0.5 (0x00008000)1828fxpLocation = fxpLocationOnFloorHalfTessFactor * (FXP_ONE - TessFactorCtx.fxpHalfTessFactorFraction) +1829fxpLocationOnCeilHalfTessFactor * (TessFactorCtx.fxpHalfTessFactorFraction);1830fxpLocation = (fxpLocation + FXP_ONE_HALF/*round*/) >> FXP_FRACTION_BITS; // get back to n.161831/* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.1832if( bFlip )1833location = 1.0f - location; // complement produces cleansed result.1834else1835CleanseParameter(location);1836*/1837if( bFlip )1838{1839fxpLocation = FXP_ONE - fxpLocation;1840}1841}18421843//---------------------------------------------------------------------------------------------------------------------------------1844// CHWTessellator::StitchRegular1845//---------------------------------------------------------------------------------------------------------------------------------1846void CHWTessellator::StitchRegular(bool bTrapezoid,DIAGONALS diagonals,1847int baseIndexOffset, int numInsideEdgePoints,1848int insideEdgePointBaseOffset, int outsideEdgePointBaseOffset)1849{1850int insidePoint = insideEdgePointBaseOffset;1851int outsidePoint = outsideEdgePointBaseOffset;1852if( bTrapezoid )1853{1854DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);1855baseIndexOffset += 3; outsidePoint++;1856}1857int p;1858switch( diagonals )1859{1860case DIAGONALS_INSIDE_TO_OUTSIDE:1861// Diagonals pointing from inside edge forward towards outside edge1862for( p = 0; p < numInsideEdgePoints-1; p++ )1863{1864DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);1865baseIndexOffset += 3;18661867DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1868baseIndexOffset += 3;1869insidePoint++; outsidePoint++;1870}1871break;1872case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation1873// Diagonals pointing from outside edge forward towards inside edge18741875// First half1876for( p = 0; p < numInsideEdgePoints/2-1; p++ )1877{1878DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);1879baseIndexOffset += 3;1880DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1881baseIndexOffset += 3;1882insidePoint++; outsidePoint++;1883}18841885// Middle1886DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);1887baseIndexOffset += 3;1888DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1889baseIndexOffset += 3;1890insidePoint++; outsidePoint++; p+=2;18911892// Second half1893for( ; p < numInsideEdgePoints; p++ )1894{1895DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);1896baseIndexOffset += 3;1897DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1898baseIndexOffset += 3;1899insidePoint++; outsidePoint++;1900}1901break;1902case DIAGONALS_MIRRORED:1903// First half, diagonals pointing from outside of outside edge to inside of inside edge1904for( p = 0; p < numInsideEdgePoints/2; p++ )1905{1906DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);1907baseIndexOffset += 3;1908DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1909baseIndexOffset += 3;1910insidePoint++; outsidePoint++;1911}1912// Second half, diagonals pointing from inside of inside edge to outside of outside edge1913for( ; p < numInsideEdgePoints-1; p++ )1914{1915DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);1916baseIndexOffset += 3;1917DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);1918baseIndexOffset += 3;1919insidePoint++; outsidePoint++;1920}1921break;1922}1923if( bTrapezoid )1924{1925DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);1926baseIndexOffset += 3;1927}1928}19291930//---------------------------------------------------------------------------------------------------------------------------------1931// CHWTessellator::StitchTransition()1932//---------------------------------------------------------------------------------------------------------------------------------1933void CHWTessellator::StitchTransition(int baseIndexOffset,1934int insideEdgePointBaseOffset, int insideNumHalfTessFactorPoints,1935TESSELLATOR_PARITY insideEdgeTessFactorParity,1936int outsideEdgePointBaseOffset, int outsideNumHalfTessFactorPoints,1937TESSELLATOR_PARITY outsideTessFactorParity1938)1939{1940// Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.1941// The stitching order is governed by Ruler Function vertex split ordering (see external documentation).1942//1943// The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge1944// at the max tessellation amount given ruler-function split order.1945// Recall the other half of an edge is mirrored, so we only need to deal with one half.1946// This table is used to decide when to advance a point on the interior or exterior.1947// It supports odd TessFactor up to 65 and even TessFactor up to 64.1948static const int finalPointPositionTable[33] =1949{ 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,19501, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };19511952// The loopStart and loopEnd tables below just provide optimal loop bounds for the1953// stitching algorithm further below, for any given halfTssFactor.1954// There is probably a better way to encode this...19551956// loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is1957// less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.1958static const int loopStart[33] =1959{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};1960// loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is1961// less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.1962static const int loopEnd[33] =1963{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};19641965if( TESSELLATOR_PARITY_ODD == insideEdgeTessFactorParity )1966{1967insideNumHalfTessFactorPoints -= 1;1968}1969if( TESSELLATOR_PARITY_ODD == outsideTessFactorParity )1970{1971outsideNumHalfTessFactorPoints -= 1;1972}1973// Walk first half1974int outsidePoint = outsideEdgePointBaseOffset;1975int insidePoint = insideEdgePointBaseOffset;19761977// iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 311978int iStart = min(loopStart[insideNumHalfTessFactorPoints],loopStart[outsideNumHalfTessFactorPoints]);1979int iEnd = max(loopEnd[insideNumHalfTessFactorPoints],loopEnd[outsideNumHalfTessFactorPoints]);19801981if( finalPointPositionTable[0] < outsideNumHalfTessFactorPoints ) // since we dont' start the loop at 0 below, we need a special case.1982{1983// Advance outside1984DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);1985baseIndexOffset += 3; outsidePoint++;1986}19871988for(int i = iStart; i <= iEnd; i++)1989{1990if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable[i] < insideNumHalfTessFactorPoints))1991{1992// Advance inside1993DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);1994baseIndexOffset += 3; insidePoint++;1995}1996if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))1997{1998// Advance outside1999DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);2000baseIndexOffset += 3; outsidePoint++;2001}2002}20032004if( (insideEdgeTessFactorParity != outsideTessFactorParity) || (insideEdgeTessFactorParity == TESSELLATOR_PARITY_ODD))2005{2006if( insideEdgeTessFactorParity == outsideTessFactorParity )2007{2008// Quad in the middle2009DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);2010baseIndexOffset += 3;2011DefineClockwiseTriangle(insidePoint+1,outsidePoint,outsidePoint+1,baseIndexOffset);2012baseIndexOffset += 3;2013insidePoint++;2014outsidePoint++;2015}2016else if( TESSELLATOR_PARITY_EVEN == insideEdgeTessFactorParity )2017{2018// Triangle pointing inside2019DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);2020baseIndexOffset += 3;2021outsidePoint++;2022}2023else2024{2025// Triangle pointing outside2026DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);2027baseIndexOffset += 3;2028insidePoint++;2029}2030}20312032// Walk second half.2033for(int i = iEnd; i >= iStart; i--)2034{2035if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))2036{2037// Advance outside2038DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);2039baseIndexOffset += 3; outsidePoint++;2040}2041if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable[i] < insideNumHalfTessFactorPoints))2042{2043// Advance inside2044DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);2045baseIndexOffset += 3; insidePoint++;2046}2047}2048// Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.2049if((finalPointPositionTable[0] < outsideNumHalfTessFactorPoints))2050{2051DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);2052baseIndexOffset += 3; outsidePoint++;2053}2054}20552056//---------------------------------------------------------------------------------------------------------------------------------2057// CHWTessellator::PatchIndexValue()2058//--------------------------------------------------------------------------------------------------------------------------------2059int CHWTessellator::PatchIndexValue(int index)2060{2061if( m_bUsingPatchedIndices )2062{2063if( index >= m_IndexPatchContext.outsidePointIndexPatchBase ) // assumed remapped outide indices are > remapped inside vertices2064{2065if( index == m_IndexPatchContext.outsidePointIndexBadValue )2066index = m_IndexPatchContext.outsidePointIndexReplacementValue;2067else2068index += m_IndexPatchContext.outsidePointIndexDeltaToRealValue;2069}2070else2071{2072if( index == m_IndexPatchContext.insidePointIndexBadValue )2073index = m_IndexPatchContext.insidePointIndexReplacementValue;2074else2075index += m_IndexPatchContext.insidePointIndexDeltaToRealValue;2076}2077}2078else if( m_bUsingPatchedIndices2 )2079{2080if( index >= m_IndexPatchContext2.baseIndexToInvert )2081{2082if( index == m_IndexPatchContext2.cornerCaseBadValue )2083{2084index = m_IndexPatchContext2.cornerCaseReplacementValue;2085}2086else2087{2088index = m_IndexPatchContext2.indexInversionEndPoint - index;2089}2090}2091else if( index == m_IndexPatchContext2.cornerCaseBadValue )2092{2093index = m_IndexPatchContext2.cornerCaseReplacementValue;2094}2095}2096return index;2097}209820992100//=================================================================================================================================2101// CHLSLTessellator2102//=================================================================================================================================21032104//---------------------------------------------------------------------------------------------------------------------------------2105// CHLSLTessellator::CHLSLTessellator2106//---------------------------------------------------------------------------------------------------------------------------------2107CHLSLTessellator::CHLSLTessellator()2108{2109m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =2110m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;2111}21122113//---------------------------------------------------------------------------------------------------------------------------------2114// CHLSLTessellator::Init2115// User calls this.2116//---------------------------------------------------------------------------------------------------------------------------------2117void CHLSLTessellator::Init(2118PIPE_TESSELLATOR_PARTITIONING partitioning,2119PIPE_TESSELLATOR_REDUCTION insideTessFactorReduction,2120PIPE_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis,2121PIPE_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive)2122{2123CHWTessellator::Init(partitioning,outputPrimitive);2124m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =2125m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;2126m_partitioning = partitioning;2127m_originalPartitioning = partitioning;2128switch( partitioning )2129{2130case PIPE_TESSELLATOR_PARTITIONING_INTEGER:2131default:2132break;2133case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:2134m_parity = TESSELLATOR_PARITY_ODD;2135break;2136case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:2137m_parity = TESSELLATOR_PARITY_EVEN;2138break;2139}2140m_originalParity = m_parity;2141m_outputPrimitive = outputPrimitive;2142m_insideTessFactorReduction = insideTessFactorReduction;2143m_quadInsideTessFactorReductionAxis = quadInsideTessFactorReductionAxis;2144}2145//---------------------------------------------------------------------------------------------------------------------------------2146// CHLSLTessellator::TessellateQuadDomain2147// User calls this2148//---------------------------------------------------------------------------------------------------------------------------------2149void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,2150float insideTessFactorScaleU, float insideTessFactorScaleV )2151{2152QuadHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactorScaleU,insideTessFactorScaleV);21532154CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3],2155m_LastComputedTessFactors[4],m_LastComputedTessFactors[5]);2156}21572158//---------------------------------------------------------------------------------------------------------------------------------2159// CHLSLTessellator::QuadHLSLProcessTessFactors2160//---------------------------------------------------------------------------------------------------------------------------------2161void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,2162float insideTessFactorScaleU, float insideTessFactorScaleV )2163{2164if( !(tessFactor_Ueq0 > 0) ||// NaN will pass2165!(tessFactor_Veq0 > 0) ||2166!(tessFactor_Ueq1 > 0) ||2167!(tessFactor_Veq1 > 0) )2168{2169m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;2170m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;2171m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;2172m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;2173m_LastUnRoundedComputedTessFactors[4] = 0;2174m_LastUnRoundedComputedTessFactors[5] = 0;2175m_LastComputedTessFactors[0] =2176m_LastComputedTessFactors[1] =2177m_LastComputedTessFactors[2] =2178m_LastComputedTessFactors[3] =2179m_LastComputedTessFactors[4] =2180m_LastComputedTessFactors[5] = 0;2181return;2182}21832184CleanupFloatTessFactor(tessFactor_Ueq0);// clamp to [1.0f..INF], NaN->1.0f2185CleanupFloatTessFactor(tessFactor_Veq0);2186CleanupFloatTessFactor(tessFactor_Ueq1);2187CleanupFloatTessFactor(tessFactor_Veq1);21882189// Save off tessFactors so they can be returned to app2190m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;2191m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;2192m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;2193m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;21942195// Process outside tessFactors2196float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};2197int edge, axis;2198TESSELLATOR_PARITY insideTessFactorParity[QUAD_AXES];2199if( Pow2Partitioning() || IntegerPartitioning() )2200{2201for( edge = 0; edge < QUAD_EDGES; edge++ )2202{2203RoundUpTessFactor(outsideTessFactor[edge]);2204ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode2205}2206}2207else2208{2209SetTessellationParity(m_originalParity); // ClampTessFactor needs it2210for( edge = 0; edge < QUAD_EDGES; edge++ )2211{2212ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode2213}2214}22152216// Compute inside TessFactors2217float insideTessFactor[QUAD_AXES];2218if( m_quadInsideTessFactorReductionAxis == PIPE_TESSELLATOR_QUAD_REDUCTION_1_AXIS )2219{2220switch( m_insideTessFactorReduction )2221{2222case PIPE_TESSELLATOR_REDUCTION_MIN:2223insideTessFactor[U] = tess_fmin(tess_fmin(tessFactor_Veq0,tessFactor_Veq1),tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1));2224break;2225case PIPE_TESSELLATOR_REDUCTION_MAX:2226insideTessFactor[U] = tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));2227break;2228case PIPE_TESSELLATOR_REDUCTION_AVERAGE:2229insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4;2230break;2231default:2232unreachable("impossible m_insideTessFactorReduction");2233}2234// Scale inside tessFactor based on user scale factor.22352236ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->02237insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;22382239// Compute inside parity2240if( Pow2Partitioning() || IntegerPartitioning() )2241{2242ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input2243m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app2244RoundUpTessFactor(insideTessFactor[U]);2245insideTessFactorParity[U] =2246insideTessFactorParity[V] =2247(isEven(insideTessFactor[U]) || (FLOAT_ONE == insideTessFactor[U]) )2248? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2249}2250else2251{2252ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input2253m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app2254// no parity changes for fractional tessellation - just use what the user requested2255insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;2256}22572258// To prevent snapping on edges, the "picture frame" comes2259// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.2260if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&2261(insideTessFactor[U] < FLOAT_THREE) )2262{2263if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)2264{2265insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1)));2266}2267else2268{2269insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4);2270}2271ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input2272m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app2273if( IntegerPartitioning())2274{2275RoundUpTessFactor(insideTessFactor[U]);2276insideTessFactorParity[U] =2277insideTessFactorParity[V] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2278}2279}2280insideTessFactor[V] = insideTessFactor[U];2281}2282else2283{2284switch( m_insideTessFactorReduction )2285{2286case PIPE_TESSELLATOR_REDUCTION_MIN:2287insideTessFactor[U] = tess_fmin(tessFactor_Veq0,tessFactor_Veq1);2288insideTessFactor[V] = tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1);2289break;2290case PIPE_TESSELLATOR_REDUCTION_MAX:2291insideTessFactor[U] = tess_fmax(tessFactor_Veq0,tessFactor_Veq1);2292insideTessFactor[V] = tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1);2293break;2294case PIPE_TESSELLATOR_REDUCTION_AVERAGE:2295insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1) / 2;2296insideTessFactor[V] = (tessFactor_Ueq0 + tessFactor_Ueq1) / 2;2297break;2298default:2299unreachable("impossible m_insideTessFactorReduction");2300}2301// Scale inside tessFactors based on user scale factor.23022303ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->02304ClampFloatTessFactorScale(insideTessFactorScaleV);2305insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;2306insideTessFactor[V] = insideTessFactor[V]*insideTessFactorScaleV;23072308// Compute inside parity2309if( Pow2Partitioning() || IntegerPartitioning() )2310{2311for( axis = 0; axis < QUAD_AXES; axis++ )2312{2313ClampTessFactor(insideTessFactor[axis]); // clamp reduction + scale result that is based on unbounded user input2314m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app2315RoundUpTessFactor(insideTessFactor[axis]);2316insideTessFactorParity[axis] =2317(isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )2318? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2319}2320}2321else2322{2323ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input2324ClampTessFactor(insideTessFactor[V]); // clamp reduction + scale result that is based on unbounded user input2325m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app2326m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app2327// no parity changes for fractional tessellation - just use what the user requested2328insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;2329}23302331// To prevent snapping on edges, the "picture frame" comes2332// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.2333if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&2334(insideTessFactor[U] < FLOAT_THREE) )2335{2336if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)2337{2338insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Veq0,tessFactor_Veq1));2339}2340else2341{2342insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1) / 2);2343}2344ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input2345m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app2346if( IntegerPartitioning())2347{2348RoundUpTessFactor(insideTessFactor[U]);2349insideTessFactorParity[U] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2350}2351}23522353if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[V]) &&2354(insideTessFactor[V] < FLOAT_THREE) )2355{2356if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)2357{2358insideTessFactor[V] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));2359}2360else2361{2362insideTessFactor[V] = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Ueq1) / 2);2363}2364ClampTessFactor(insideTessFactor[V]);// clamp reduction result that is based on unbounded user input2365m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app2366if( IntegerPartitioning())2367{2368RoundUpTessFactor(insideTessFactor[V]);2369insideTessFactorParity[V] = isEven(insideTessFactor[V]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2370}2371}23722373for( axis = 0; axis < QUAD_AXES; axis++ )2374{2375if( TESSELLATOR_PARITY_ODD == insideTessFactorParity[axis] )2376{2377// Ensure the first ring ("picture frame") interpolates in on all sides2378// as much as the side with the minimum TessFactor. Prevents snapping to edge.2379if( (insideTessFactor[axis] < FLOAT_THREE) && (insideTessFactor[axis] < insideTessFactor[(axis+1)&0x1]))2380{2381insideTessFactor[axis] = tess_fmin(insideTessFactor[(axis+1)&0x1],FLOAT_THREE);2382m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app2383}2384}2385}2386}23872388// Save off TessFactors so they can be returned to app2389m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];2390m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];2391m_LastComputedTessFactors[2] = outsideTessFactor[Ueq1];2392m_LastComputedTessFactors[3] = outsideTessFactor[Veq1];2393m_LastComputedTessFactors[4] = insideTessFactor[U];2394m_LastComputedTessFactors[5] = insideTessFactor[V];2395}23962397//---------------------------------------------------------------------------------------------------------------------------------2398// CHLSLTessellator::TessellateTriDomain2399// User calls this2400//---------------------------------------------------------------------------------------------------------------------------------2401void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,2402float insideTessFactorScale )2403{2404TriHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactorScale);24052406CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3]);2407}24082409//---------------------------------------------------------------------------------------------------------------------------------2410// CHLSLTessellator::TriHLSLProcessTessFactors2411//---------------------------------------------------------------------------------------------------------------------------------2412void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,2413float insideTessFactorScale )2414{2415if( !(tessFactor_Ueq0 > 0) || // NaN will pass2416!(tessFactor_Veq0 > 0) ||2417!(tessFactor_Weq0 > 0) )2418{2419m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;2420m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;2421m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;2422m_LastUnRoundedComputedTessFactors[3] =2423m_LastComputedTessFactors[0] =2424m_LastComputedTessFactors[1] =2425m_LastComputedTessFactors[2] =2426m_LastComputedTessFactors[3] = 0;2427return;2428}24292430CleanupFloatTessFactor(tessFactor_Ueq0); // clamp to [1.0f..INF], NaN->1.0f2431CleanupFloatTessFactor(tessFactor_Veq0);2432CleanupFloatTessFactor(tessFactor_Weq0);24332434// Save off TessFactors so they can be returned to app2435m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;2436m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;2437m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;24382439// Process outside TessFactors2440float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};2441int edge;2442if( Pow2Partitioning() || IntegerPartitioning() )2443{2444for( edge = 0; edge < TRI_EDGES; edge++ )2445{2446RoundUpTessFactor(outsideTessFactor[edge]); // for pow2 this rounds to pow22447ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode2448}2449}2450else2451{2452for( edge = 0; edge < TRI_EDGES; edge++ )2453{2454ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode2455}2456}24572458// Compute inside TessFactor2459float insideTessFactor;2460switch( m_insideTessFactorReduction )2461{2462case PIPE_TESSELLATOR_REDUCTION_MIN:2463insideTessFactor = tess_fmin(tess_fmin(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);2464break;2465case PIPE_TESSELLATOR_REDUCTION_MAX:2466insideTessFactor = tess_fmax(tess_fmax(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);2467break;2468case PIPE_TESSELLATOR_REDUCTION_AVERAGE:2469insideTessFactor = (tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3;2470break;2471default:2472unreachable("impossible m_insideTessFactorReduction");2473}24742475// Scale inside TessFactor based on user scale factor.2476ClampFloatTessFactorScale(insideTessFactorScale); // clamp scale value to [0..1], NaN->02477insideTessFactor = insideTessFactor*tess_fmin(FLOAT_ONE,insideTessFactorScale);24782479ClampTessFactor(insideTessFactor); // clamp reduction + scale result that is based on unbounded user input2480m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app2481TESSELLATOR_PARITY parity;2482if( Pow2Partitioning() || IntegerPartitioning() )2483{2484RoundUpTessFactor(insideTessFactor);2485parity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))2486? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;2487}2488else2489{2490parity = m_originalParity;2491}24922493if( (TESSELLATOR_PARITY_ODD == parity) &&2494(insideTessFactor < FLOAT_THREE))2495{2496// To prevent snapping on edges, the "picture frame" comes2497// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.2498if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)2499{2500insideTessFactor = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tess_fmax(tessFactor_Veq0,tessFactor_Weq0)));2501}2502else2503{2504insideTessFactor = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3);2505}2506ClampTessFactor(insideTessFactor); // clamp reduction result that is based on unbounded user input2507m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app2508if( IntegerPartitioning())2509{2510RoundUpTessFactor(insideTessFactor);2511}2512}25132514// Save off TessFactors so they can be returned to app2515m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];2516m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];2517m_LastComputedTessFactors[2] = outsideTessFactor[Weq0];2518m_LastComputedTessFactors[3] = insideTessFactor;2519}25202521//---------------------------------------------------------------------------------------------------------------------------------2522// CHLSLTessellator::TessellateIsoLineDomain2523// User calls this.2524//---------------------------------------------------------------------------------------------------------------------------------2525void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail, float TessFactor_V_LineDensity )2526{2527IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail);2528CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1]);2529}25302531//---------------------------------------------------------------------------------------------------------------------------------2532// CHLSLTessellator::IsoLineHLSLProcessTessFactors2533//---------------------------------------------------------------------------------------------------------------------------------2534void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )2535{2536if( !(TessFactor_V_LineDensity > 0) || // NaN will pass2537!(TessFactor_U_LineDetail > 0) )2538{2539m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity;2540m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail;2541m_LastComputedTessFactors[0] =2542m_LastComputedTessFactors[1] = 0;2543return;2544}25452546CleanupFloatTessFactor(TessFactor_V_LineDensity); // clamp to [1.0f..INF], NaN->1.0f2547CleanupFloatTessFactor(TessFactor_U_LineDetail); // clamp to [1.0f..INF], NaN->1.0f25482549ClampTessFactor(TessFactor_U_LineDetail); // clamp unbounded user input based on tessellation mode25502551m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail; // Save off TessFactors so they can be returned to app25522553if(Pow2Partitioning()||IntegerPartitioning())2554{2555RoundUpTessFactor(TessFactor_U_LineDetail);2556}25572558OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);25592560ClampTessFactor(TessFactor_V_LineDensity); // Clamp unbounded user input to integer2561m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity; // Save off TessFactors so they can be returned to app25622563RoundUpTessFactor(TessFactor_V_LineDensity);25642565RestorePartitioning();25662567// Save off TessFactors so they can be returned to app2568m_LastComputedTessFactors[0] = TessFactor_V_LineDensity;2569m_LastComputedTessFactors[1] = TessFactor_U_LineDetail;2570}25712572//---------------------------------------------------------------------------------------------------------------------------------2573// CHLSLTessellator::ClampTessFactor()2574//---------------------------------------------------------------------------------------------------------------------------------2575void CHLSLTessellator::ClampTessFactor(float& TessFactor)2576{2577if( Pow2Partitioning() )2578{2579TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );2580}2581else if( IntegerPartitioning() )2582{2583TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );2584}2585else if( Odd() )2586{2587TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );2588}2589else // even2590{2591TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR) );2592}2593}25942595//---------------------------------------------------------------------------------------------------------------------------------2596// CHLSLTessellator::CleanupFloatTessFactor()2597//---------------------------------------------------------------------------------------------------------------------------------2598static const int exponentMask = 0x7f800000;2599static const int mantissaMask = 0x007fffff;2600void CHLSLTessellator::CleanupFloatTessFactor(float& input)2601{2602// If input is < 1.0f or NaN, clamp to 1.0f.2603// In other words, clamp input to [1.0f...+INF]2604int bits = *(int*)&input;2605if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?2606(input < 1.0f) )2607{2608input = 1;2609}2610}26112612//---------------------------------------------------------------------------------------------------------------------------------2613// CHLSLTessellator::ClampFloatTessFactorScale()2614//---------------------------------------------------------------------------------------------------------------------------------2615void CHLSLTessellator::ClampFloatTessFactorScale(float& input)2616{2617// If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.2618// In other words, clamp input to [0.0f...1.0f]2619int bits = *(int*)&input;2620if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?2621(input < 0.0f) )2622{2623input = 0;2624}2625else if( input > 1 )2626{2627input = 1;2628}2629}26302631//---------------------------------------------------------------------------------------------------------------------------------2632// CHLSLTessellator::RoundUpTessFactor()2633//---------------------------------------------------------------------------------------------------------------------------------2634static const int exponentLSB = 0x00800000;2635void CHLSLTessellator::RoundUpTessFactor(float& TessFactor)2636{2637// Assume TessFactor is in [1.0f..+INF]2638if( Pow2Partitioning() )2639{2640int bits = *(int*)&TessFactor;2641if( bits & mantissaMask )2642{2643*(int*)&TessFactor = (bits & exponentMask) + exponentLSB;2644}2645}2646else if( IntegerPartitioning() )2647{2648TessFactor = ceil(TessFactor);2649}2650}265126522653