You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1184 lines
43 KiB
1184 lines
43 KiB
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
using System;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition
|
|
{
|
|
internal enum BinaryFunc
|
|
{
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Min,
|
|
Max,
|
|
Pow,
|
|
Reflect,
|
|
Num
|
|
};
|
|
|
|
internal enum SingleFunc
|
|
{
|
|
Saturate,
|
|
Rcp,
|
|
Sqr,
|
|
Log,
|
|
Log2,
|
|
Log10,
|
|
Exp,
|
|
Exp2,
|
|
Sqrt,
|
|
Rsqrt,
|
|
Normalize,
|
|
Frac,
|
|
Cos,
|
|
CosH,
|
|
Sin,
|
|
SinH,
|
|
Tan,
|
|
TanH,
|
|
Abs,
|
|
Negate,
|
|
Floor,
|
|
Ceil,
|
|
Num
|
|
};
|
|
|
|
// These ops have different rules than the BinaryFunc/SingleFunc ops above. For examples,
|
|
// length always returns a scalar type (even if the input is a vector).
|
|
internal enum Func1
|
|
{
|
|
Len,
|
|
LenSqr,
|
|
InvLen,
|
|
InvLenSqr,
|
|
Num
|
|
};
|
|
|
|
internal enum Func2
|
|
{
|
|
Dot,
|
|
Cross,
|
|
Num
|
|
};
|
|
|
|
internal enum Func3
|
|
{
|
|
Lerp,
|
|
Num
|
|
};
|
|
|
|
internal enum TexSampleFunc
|
|
{
|
|
Tex2D,
|
|
Tex2DArray,
|
|
TexCube,
|
|
Tex3D,
|
|
}
|
|
|
|
internal enum TexSampleType
|
|
{
|
|
Lod0,
|
|
Fpd,
|
|
Apd,
|
|
Apd_3x,
|
|
Num
|
|
};
|
|
|
|
// APD = Analytic Partial Derivative
|
|
enum ApdStatus
|
|
{
|
|
Unknown, // not known yet, used for cases when we haven't traversed this node yet
|
|
Zero, // known to be zero, such as uniforms or values derived from uniforms
|
|
NotNeeded, // known to not be needed by anything, so are not going to keep track of it. treated as zero.
|
|
Valid, // valid. we need to evaluate this node's apd because we need it elsewhere
|
|
Invalid, // invalid, we need this derivative, but we don't have it. used for complicated funcs that aren't implemented yet.
|
|
Num
|
|
};
|
|
|
|
enum AttributeType
|
|
{
|
|
UV,
|
|
Color
|
|
}
|
|
|
|
internal class HlslUtil
|
|
{
|
|
// for a given parameter in a function, what kinds of apd status can we give it?
|
|
// OnlyApd: it MUST be apd (such as a texture sample)
|
|
// OnlyFpd: never is apd, such as the lod bias
|
|
// AllowApdVariation: there is an fpd/apd version of this function, but if
|
|
// one type upgrades than they all have to upgrade.
|
|
// Any: the parameter can be apd/fpd independently of any other parameter.
|
|
|
|
static internal bool IsValidSwizzleType(HlslNativeType type)
|
|
{
|
|
bool ret = false;
|
|
if (HlslNativeType._float <= type && type <= HlslNativeType._bool4)
|
|
{
|
|
ret = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static internal int GetNumRows(HlslNativeType type)
|
|
{
|
|
int ret = -1;
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._unknown: // default: unset
|
|
case HlslNativeType._invalid: // known to be invalid because something went wrong with parsing
|
|
case HlslNativeType._void:
|
|
ret = 0;
|
|
break;
|
|
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._float1:
|
|
case HlslNativeType._float2:
|
|
case HlslNativeType._float3:
|
|
case HlslNativeType._float4:
|
|
|
|
case HlslNativeType._int:
|
|
case HlslNativeType._int1:
|
|
case HlslNativeType._int2:
|
|
case HlslNativeType._int3:
|
|
case HlslNativeType._int4:
|
|
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._half1:
|
|
case HlslNativeType._half2:
|
|
case HlslNativeType._half3:
|
|
case HlslNativeType._half4:
|
|
|
|
case HlslNativeType._uint:
|
|
case HlslNativeType._uint1:
|
|
case HlslNativeType._uint2:
|
|
case HlslNativeType._uint3:
|
|
case HlslNativeType._uint4:
|
|
|
|
case HlslNativeType._bool:
|
|
case HlslNativeType._bool1:
|
|
case HlslNativeType._bool2:
|
|
case HlslNativeType._bool3:
|
|
case HlslNativeType._bool4:
|
|
|
|
case HlslNativeType._float1x2:
|
|
case HlslNativeType._int1x2:
|
|
case HlslNativeType._half1x2:
|
|
case HlslNativeType._uint1x2:
|
|
case HlslNativeType._bool1x2:
|
|
case HlslNativeType._float1x3:
|
|
case HlslNativeType._int1x3:
|
|
case HlslNativeType._half1x3:
|
|
case HlslNativeType._uint1x3:
|
|
case HlslNativeType._bool1x3:
|
|
case HlslNativeType._float1x4:
|
|
case HlslNativeType._int1x4:
|
|
case HlslNativeType._half1x4:
|
|
case HlslNativeType._uint1x4:
|
|
case HlslNativeType._bool1x4:
|
|
return 1;
|
|
|
|
case HlslNativeType._float2x2:
|
|
case HlslNativeType._int2x2:
|
|
case HlslNativeType._half2x2:
|
|
case HlslNativeType._uint2x2:
|
|
case HlslNativeType._bool2x2:
|
|
case HlslNativeType._float2x3:
|
|
case HlslNativeType._int2x3:
|
|
case HlslNativeType._half2x3:
|
|
case HlslNativeType._uint2x3:
|
|
case HlslNativeType._bool2x3:
|
|
case HlslNativeType._float2x4:
|
|
case HlslNativeType._int2x4:
|
|
case HlslNativeType._half2x4:
|
|
case HlslNativeType._uint2x4:
|
|
case HlslNativeType._bool2x4:
|
|
return 2;
|
|
|
|
case HlslNativeType._float3x2:
|
|
case HlslNativeType._int3x2:
|
|
case HlslNativeType._half3x2:
|
|
case HlslNativeType._uint3x2:
|
|
case HlslNativeType._bool3x2:
|
|
case HlslNativeType._float3x3:
|
|
case HlslNativeType._int3x3:
|
|
case HlslNativeType._half3x3:
|
|
case HlslNativeType._uint3x3:
|
|
case HlslNativeType._bool3x3:
|
|
case HlslNativeType._float3x4:
|
|
case HlslNativeType._int3x4:
|
|
case HlslNativeType._half3x4:
|
|
case HlslNativeType._uint3x4:
|
|
case HlslNativeType._bool3x4:
|
|
return 3;
|
|
|
|
case HlslNativeType._float4x2:
|
|
case HlslNativeType._int4x2:
|
|
case HlslNativeType._half4x2:
|
|
case HlslNativeType._uint4x2:
|
|
case HlslNativeType._bool4x2:
|
|
case HlslNativeType._float4x3:
|
|
case HlslNativeType._int4x3:
|
|
case HlslNativeType._half4x3:
|
|
case HlslNativeType._uint4x3:
|
|
case HlslNativeType._bool4x3:
|
|
case HlslNativeType._float4x4:
|
|
case HlslNativeType._int4x4:
|
|
case HlslNativeType._half4x4:
|
|
case HlslNativeType._uint4x4:
|
|
case HlslNativeType._bool4x4:
|
|
return 4;
|
|
|
|
case HlslNativeType._Texture:
|
|
case HlslNativeType._Texture1D:
|
|
case HlslNativeType._Texture1DArray:
|
|
case HlslNativeType._Texture2D:
|
|
case HlslNativeType._Texture2DArray:
|
|
case HlslNativeType._Texture3D:
|
|
case HlslNativeType._TextureCUBE:
|
|
case HlslNativeType._TextureCUBEArray:
|
|
case HlslNativeType._SamplerState:
|
|
case HlslNativeType._SamplerComparisonState:
|
|
|
|
case HlslNativeType._RWTexture2D:
|
|
case HlslNativeType._RWTexture2DArray:
|
|
case HlslNativeType._RWTexture3D:
|
|
|
|
case HlslNativeType._struct: // user defined: of course
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static internal int GetNumCols(HlslNativeType type)
|
|
{
|
|
int ret = -1;
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._unknown: // default: unset
|
|
case HlslNativeType._invalid: // known to be invalid because something went wrong with parsing
|
|
case HlslNativeType._void:
|
|
ret = 0;
|
|
break;
|
|
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._float1:
|
|
case HlslNativeType._int:
|
|
case HlslNativeType._int1:
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._half1:
|
|
case HlslNativeType._uint:
|
|
case HlslNativeType._uint1:
|
|
case HlslNativeType._bool:
|
|
case HlslNativeType._bool1:
|
|
ret = 1;
|
|
break;
|
|
|
|
case HlslNativeType._float2:
|
|
case HlslNativeType._int2:
|
|
case HlslNativeType._half2:
|
|
case HlslNativeType._uint2:
|
|
case HlslNativeType._bool2:
|
|
case HlslNativeType._float1x2:
|
|
case HlslNativeType._float2x2:
|
|
case HlslNativeType._float3x2:
|
|
case HlslNativeType._float4x2:
|
|
|
|
case HlslNativeType._int1x2:
|
|
case HlslNativeType._int2x2:
|
|
case HlslNativeType._int3x2:
|
|
case HlslNativeType._int4x2:
|
|
|
|
case HlslNativeType._half1x2:
|
|
case HlslNativeType._half2x2:
|
|
case HlslNativeType._half3x2:
|
|
case HlslNativeType._half4x2:
|
|
|
|
case HlslNativeType._uint1x2:
|
|
case HlslNativeType._uint2x2:
|
|
case HlslNativeType._uint3x2:
|
|
case HlslNativeType._uint4x2:
|
|
|
|
case HlslNativeType._bool1x2:
|
|
case HlslNativeType._bool2x2:
|
|
case HlslNativeType._bool3x2:
|
|
case HlslNativeType._bool4x2:
|
|
|
|
ret = 2;
|
|
break;
|
|
|
|
case HlslNativeType._float3:
|
|
case HlslNativeType._int3:
|
|
case HlslNativeType._half3:
|
|
case HlslNativeType._uint3:
|
|
case HlslNativeType._bool3:
|
|
case HlslNativeType._float1x3:
|
|
case HlslNativeType._float2x3:
|
|
case HlslNativeType._float3x3:
|
|
case HlslNativeType._float4x3:
|
|
|
|
case HlslNativeType._int1x3:
|
|
case HlslNativeType._int2x3:
|
|
case HlslNativeType._int3x3:
|
|
case HlslNativeType._int4x3:
|
|
|
|
case HlslNativeType._half1x3:
|
|
case HlslNativeType._half2x3:
|
|
case HlslNativeType._half3x3:
|
|
case HlslNativeType._half4x3:
|
|
|
|
case HlslNativeType._uint1x3:
|
|
case HlslNativeType._uint2x3:
|
|
case HlslNativeType._uint3x3:
|
|
case HlslNativeType._uint4x3:
|
|
|
|
case HlslNativeType._bool1x3:
|
|
case HlslNativeType._bool2x3:
|
|
case HlslNativeType._bool3x3:
|
|
case HlslNativeType._bool4x3:
|
|
|
|
ret = 3;
|
|
break;
|
|
|
|
case HlslNativeType._float4:
|
|
case HlslNativeType._int4:
|
|
case HlslNativeType._half4:
|
|
case HlslNativeType._uint4:
|
|
case HlslNativeType._bool4:
|
|
|
|
case HlslNativeType._float1x4:
|
|
case HlslNativeType._float2x4:
|
|
case HlslNativeType._float3x4:
|
|
case HlslNativeType._float4x4:
|
|
|
|
case HlslNativeType._int1x4:
|
|
case HlslNativeType._int2x4:
|
|
case HlslNativeType._int3x4:
|
|
case HlslNativeType._int4x4:
|
|
|
|
case HlslNativeType._half1x4:
|
|
case HlslNativeType._half2x4:
|
|
case HlslNativeType._half3x4:
|
|
case HlslNativeType._half4x4:
|
|
|
|
case HlslNativeType._uint1x4:
|
|
case HlslNativeType._uint2x4:
|
|
case HlslNativeType._uint3x4:
|
|
case HlslNativeType._uint4x4:
|
|
|
|
case HlslNativeType._bool1x4:
|
|
case HlslNativeType._bool2x4:
|
|
case HlslNativeType._bool3x4:
|
|
case HlslNativeType._bool4x4:
|
|
ret = 4;
|
|
break;
|
|
|
|
case HlslNativeType._Texture:
|
|
case HlslNativeType._Texture1D:
|
|
case HlslNativeType._Texture1DArray:
|
|
case HlslNativeType._Texture2D:
|
|
case HlslNativeType._Texture2DArray:
|
|
case HlslNativeType._Texture3D:
|
|
case HlslNativeType._TextureCUBE:
|
|
case HlslNativeType._TextureCUBEArray:
|
|
case HlslNativeType._SamplerState:
|
|
case HlslNativeType._SamplerComparisonState:
|
|
|
|
case HlslNativeType._RWTexture2D:
|
|
case HlslNativeType._RWTexture2DArray:
|
|
case HlslNativeType._RWTexture3D:
|
|
|
|
case HlslNativeType._struct: // user defined: of course
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// a "scalar" type is really anything that we can reasonably cast to a float
|
|
static internal bool IsNativeTypeScalar(HlslNativeType type)
|
|
{
|
|
HlslNativeType baseType = GetNativeBaseType(type);
|
|
|
|
bool ret = false;
|
|
switch (baseType)
|
|
{
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._int:
|
|
case HlslNativeType._uint:
|
|
ret = true;
|
|
break;
|
|
default:
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static internal HlslNativeType GetNativeBaseType(HlslNativeType type)
|
|
{
|
|
HlslNativeType ret = HlslNativeType._invalid;
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._float1:
|
|
case HlslNativeType._float2:
|
|
case HlslNativeType._float1x2:
|
|
case HlslNativeType._float2x2:
|
|
case HlslNativeType._float3x2:
|
|
case HlslNativeType._float4x2:
|
|
case HlslNativeType._float3:
|
|
case HlslNativeType._float1x3:
|
|
case HlslNativeType._float2x3:
|
|
case HlslNativeType._float3x3:
|
|
case HlslNativeType._float4x3:
|
|
case HlslNativeType._float4:
|
|
case HlslNativeType._float1x4:
|
|
case HlslNativeType._float2x4:
|
|
case HlslNativeType._float3x4:
|
|
case HlslNativeType._float4x4:
|
|
ret = HlslNativeType._float;
|
|
break;
|
|
|
|
case HlslNativeType._int:
|
|
case HlslNativeType._int1:
|
|
case HlslNativeType._int2:
|
|
case HlslNativeType._int1x2:
|
|
case HlslNativeType._int2x2:
|
|
case HlslNativeType._int3x2:
|
|
case HlslNativeType._int4x2:
|
|
case HlslNativeType._int3:
|
|
case HlslNativeType._int1x3:
|
|
case HlslNativeType._int2x3:
|
|
case HlslNativeType._int3x3:
|
|
case HlslNativeType._int4x3:
|
|
case HlslNativeType._int4:
|
|
case HlslNativeType._int1x4:
|
|
case HlslNativeType._int2x4:
|
|
case HlslNativeType._int3x4:
|
|
case HlslNativeType._int4x4:
|
|
ret = HlslNativeType._int;
|
|
break;
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._half1:
|
|
case HlslNativeType._half2:
|
|
case HlslNativeType._half1x2:
|
|
case HlslNativeType._half2x2:
|
|
case HlslNativeType._half3x2:
|
|
case HlslNativeType._half4x2:
|
|
case HlslNativeType._half3:
|
|
case HlslNativeType._half1x3:
|
|
case HlslNativeType._half2x3:
|
|
case HlslNativeType._half3x3:
|
|
case HlslNativeType._half4x3:
|
|
case HlslNativeType._half4:
|
|
case HlslNativeType._half1x4:
|
|
case HlslNativeType._half2x4:
|
|
case HlslNativeType._half3x4:
|
|
case HlslNativeType._half4x4:
|
|
ret = HlslNativeType._half;
|
|
break;
|
|
|
|
case HlslNativeType._uint:
|
|
case HlslNativeType._uint1:
|
|
case HlslNativeType._uint2:
|
|
case HlslNativeType._uint1x2:
|
|
case HlslNativeType._uint2x2:
|
|
case HlslNativeType._uint3x2:
|
|
case HlslNativeType._uint4x2:
|
|
case HlslNativeType._uint3:
|
|
case HlslNativeType._uint1x3:
|
|
case HlslNativeType._uint2x3:
|
|
case HlslNativeType._uint3x3:
|
|
case HlslNativeType._uint4x3:
|
|
case HlslNativeType._uint4:
|
|
case HlslNativeType._uint1x4:
|
|
case HlslNativeType._uint2x4:
|
|
case HlslNativeType._uint3x4:
|
|
case HlslNativeType._uint4x4:
|
|
ret = HlslNativeType._uint;
|
|
break;
|
|
|
|
case HlslNativeType._bool:
|
|
case HlslNativeType._bool1:
|
|
case HlslNativeType._bool2:
|
|
case HlslNativeType._bool1x2:
|
|
case HlslNativeType._bool2x2:
|
|
case HlslNativeType._bool3x2:
|
|
case HlslNativeType._bool4x2:
|
|
case HlslNativeType._bool3:
|
|
case HlslNativeType._bool1x3:
|
|
case HlslNativeType._bool2x3:
|
|
case HlslNativeType._bool3x3:
|
|
case HlslNativeType._bool4x3:
|
|
case HlslNativeType._bool4:
|
|
case HlslNativeType._bool1x4:
|
|
case HlslNativeType._bool2x4:
|
|
case HlslNativeType._bool3x4:
|
|
case HlslNativeType._bool4x4:
|
|
ret = HlslNativeType._bool;
|
|
break;
|
|
|
|
case HlslNativeType._struct: // user defined: of course
|
|
default:
|
|
ret = type;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Only support float and half vectors. We could support matrices later.
|
|
static internal bool IsNativeTypeLegalForApd(HlslNativeType type)
|
|
{
|
|
bool ret = false;
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._float1:
|
|
case HlslNativeType._float2:
|
|
case HlslNativeType._float3:
|
|
case HlslNativeType._float4:
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._half1:
|
|
case HlslNativeType._half2:
|
|
case HlslNativeType._half3:
|
|
case HlslNativeType._half4:
|
|
ret = true;
|
|
break;
|
|
default:
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static internal HlslNativeType GetVectorFromBaseType(HlslNativeType baseType, int vecLen)
|
|
{
|
|
HlslNativeType ret = HlslNativeType._invalid;
|
|
HlslUtil.ParserAssert(1 <= vecLen && vecLen <= 4);
|
|
switch (baseType)
|
|
{
|
|
case HlslNativeType._float:
|
|
{
|
|
switch (vecLen)
|
|
{
|
|
case 1:
|
|
ret = HlslNativeType._float;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._float2;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._float3;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._float4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case HlslNativeType._half:
|
|
{
|
|
switch (vecLen)
|
|
{
|
|
case 1:
|
|
ret = HlslNativeType._half;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._half2;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._half3;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._half4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case HlslNativeType._int:
|
|
{
|
|
switch (vecLen)
|
|
{
|
|
case 1:
|
|
ret = HlslNativeType._int;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._int2;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._int3;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._int4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case HlslNativeType._uint:
|
|
{
|
|
switch (vecLen)
|
|
{
|
|
case 1:
|
|
ret = HlslNativeType._uint;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._uint2;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._uint3;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._uint4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case HlslNativeType._bool:
|
|
{
|
|
switch (vecLen)
|
|
{
|
|
case 1:
|
|
ret = HlslNativeType._bool;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._bool2;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._bool3;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._bool4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
// no op, returning _invalid seems fine.
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// helper function to convert each type into a 0-4 index
|
|
internal static int GetIndexHelperForBaseType(HlslNativeType type)
|
|
{
|
|
int ret = -1;
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._bool:
|
|
ret = 0;
|
|
break;
|
|
case HlslNativeType._uint:
|
|
ret = 1;
|
|
break;
|
|
case HlslNativeType._int:
|
|
ret = 2;
|
|
break;
|
|
case HlslNativeType._half:
|
|
ret = 3;
|
|
break;
|
|
case HlslNativeType._float:
|
|
ret = 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static HlslNativeType GetBaseTypeForIndexHelper(int index)
|
|
{
|
|
HlslNativeType ret = HlslNativeType._invalid;
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
ret = HlslNativeType._bool;
|
|
break;
|
|
case 1:
|
|
ret = HlslNativeType._uint;
|
|
break;
|
|
case 2:
|
|
ret = HlslNativeType._int;
|
|
break;
|
|
case 3:
|
|
ret = HlslNativeType._half;
|
|
break;
|
|
case 4:
|
|
ret = HlslNativeType._float;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
internal static HlslNativeType GetBaseTypeResultFromBinaryOp(HlslNativeType lhsType, HlslNativeType rhsType)
|
|
{
|
|
int lhsIndex = GetIndexHelperForBaseType(lhsType);
|
|
int rhsIndex = GetIndexHelperForBaseType(rhsType);
|
|
|
|
// The casting ruls are, AFAICT undocumented. Best answer I could find was this one:
|
|
// https://github.com/KhronosGroup/glslang/issues/449
|
|
// The main idea is:
|
|
// bool < uint < int < float < double
|
|
// That being said, it's unclear how a half fits into this. So we'll go with this for now:
|
|
// bool < uint < int < half < float < double
|
|
int dstIndex = Math.Max(lhsIndex, rhsIndex);
|
|
|
|
HlslNativeType ret = GetBaseTypeForIndexHelper(dstIndex);
|
|
return ret;
|
|
}
|
|
|
|
internal static HlslNativeType GetBaseTypeWithDims(HlslNativeType baseType, int numRows, int numCols)
|
|
{
|
|
HlslNativeType ret = HlslNativeType._invalid;
|
|
|
|
HlslNativeType[] floatTypes = new HlslNativeType[16]
|
|
{
|
|
HlslNativeType._float, HlslNativeType._float2,HlslNativeType._float3,HlslNativeType._float4,
|
|
HlslNativeType._float2, HlslNativeType._float2x2,HlslNativeType._float2x3,HlslNativeType._float2x4,
|
|
HlslNativeType._float3, HlslNativeType._float3x2,HlslNativeType._float3x3,HlslNativeType._float3x4,
|
|
HlslNativeType._float4, HlslNativeType._float4x2,HlslNativeType._float4x3,HlslNativeType._float4x4,
|
|
};
|
|
|
|
HlslNativeType[] halfTypes = new HlslNativeType[16]
|
|
{
|
|
HlslNativeType._half, HlslNativeType._half2,HlslNativeType._half3,HlslNativeType._half4,
|
|
HlslNativeType._half2, HlslNativeType._half2x2,HlslNativeType._half2x3,HlslNativeType._half2x4,
|
|
HlslNativeType._half3, HlslNativeType._half3x2,HlslNativeType._half3x3,HlslNativeType._half3x4,
|
|
HlslNativeType._half4, HlslNativeType._half4x2,HlslNativeType._half4x3,HlslNativeType._half4x4,
|
|
};
|
|
|
|
HlslNativeType[] uintTypes = new HlslNativeType[16]
|
|
{
|
|
HlslNativeType._uint, HlslNativeType._uint2,HlslNativeType._uint3,HlslNativeType._uint4,
|
|
HlslNativeType._uint2, HlslNativeType._uint2x2,HlslNativeType._uint2x3,HlslNativeType._uint2x4,
|
|
HlslNativeType._uint3, HlslNativeType._uint3x2,HlslNativeType._uint3x3,HlslNativeType._uint3x4,
|
|
HlslNativeType._uint4, HlslNativeType._uint4x2,HlslNativeType._uint4x3,HlslNativeType._uint4x4,
|
|
};
|
|
|
|
HlslNativeType[] intTypes = new HlslNativeType[16]
|
|
{
|
|
HlslNativeType._int, HlslNativeType._int2,HlslNativeType._int3,HlslNativeType._int4,
|
|
HlslNativeType._int2, HlslNativeType._int2x2,HlslNativeType._int2x3,HlslNativeType._int2x4,
|
|
HlslNativeType._int3, HlslNativeType._int3x2,HlslNativeType._int3x3,HlslNativeType._int3x4,
|
|
HlslNativeType._int4, HlslNativeType._int4x2,HlslNativeType._int4x3,HlslNativeType._int4x4,
|
|
};
|
|
|
|
HlslNativeType[] boolTypes = new HlslNativeType[16]
|
|
{
|
|
HlslNativeType._bool, HlslNativeType._bool2,HlslNativeType._bool3,HlslNativeType._bool4,
|
|
HlslNativeType._bool2, HlslNativeType._bool2x2,HlslNativeType._bool2x3,HlslNativeType._bool2x4,
|
|
HlslNativeType._bool3, HlslNativeType._bool3x2,HlslNativeType._bool3x3,HlslNativeType._bool3x4,
|
|
HlslNativeType._bool4, HlslNativeType._bool4x2,HlslNativeType._bool4x3,HlslNativeType._bool4x4,
|
|
};
|
|
|
|
int colIndex = numCols - 1;
|
|
int rowIndex = numRows - 1;
|
|
|
|
if (colIndex >= 0 && colIndex < 4 && rowIndex >= 0 && rowIndex < 4)
|
|
{
|
|
switch (baseType)
|
|
{
|
|
case HlslNativeType._float:
|
|
ret = floatTypes[rowIndex * 4 + colIndex];
|
|
break;
|
|
case HlslNativeType._half:
|
|
ret = halfTypes[rowIndex * 4 + colIndex];
|
|
break;
|
|
case HlslNativeType._int:
|
|
ret = floatTypes[rowIndex * 4 + colIndex];
|
|
break;
|
|
case HlslNativeType._uint:
|
|
ret = floatTypes[rowIndex * 4 + colIndex];
|
|
break;
|
|
case HlslNativeType._bool:
|
|
ret = floatTypes[rowIndex * 4 + colIndex];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
internal static HlslNativeType GetBinaryOpReturnType(HlslNativeType lhsType, HlslNativeType rhsType, bool isMul)
|
|
{
|
|
int lhsRows = GetNumRows(lhsType);
|
|
int lhsCols = GetNumCols(lhsType);
|
|
int rhsRows = GetNumRows(rhsType);
|
|
int rhsCols = GetNumCols(rhsType);
|
|
|
|
HlslNativeType lhsBase = GetNativeBaseType(lhsType);
|
|
HlslNativeType rhsBase = GetNativeBaseType(rhsType);
|
|
HlslNativeType dstBase = GetBaseTypeResultFromBinaryOp(lhsBase, rhsBase);
|
|
|
|
HlslNativeType dstType = HlslNativeType._invalid;
|
|
if (isMul)
|
|
{
|
|
// is either a matrix type?
|
|
bool isLhsMatrix = (lhsRows >= 2);
|
|
bool isRhsMatrix = (rhsRows >= 2);
|
|
|
|
// if either type is a scalar, simply promote to the larger type
|
|
if (lhsRows == 1 && lhsCols == 1)
|
|
{
|
|
// if lhs is scalar, then promote to rhs
|
|
dstType = GetBaseTypeWithDims(dstBase, rhsRows, rhsCols);
|
|
}
|
|
else if (rhsRows == 1 && rhsCols == 1)
|
|
{
|
|
// if rhs is scalar, then promote to lhs
|
|
dstType = GetBaseTypeWithDims(dstBase, lhsRows, lhsCols);
|
|
}
|
|
else
|
|
{
|
|
// Gets pretty messy becuase a float4 can be either a 4x1 or 1x4 vector. So if one is a matrix
|
|
// and the other is a vector, we might have to transpose the vector.
|
|
if (isLhsMatrix && isRhsMatrix)
|
|
{
|
|
// lhsCols should be the same as rhsCols, but we'll let the compiler handle that.
|
|
int dstRows = lhsRows;
|
|
int dstCols = rhsCols;
|
|
dstType = GetBaseTypeWithDims(dstBase, dstRows, dstCols);
|
|
}
|
|
else if (isLhsMatrix)
|
|
{
|
|
HlslUtil.ParserAssert(!isRhsMatrix); // should be handled by case above
|
|
// we'll assume that the rhs number of rows is the same as the lhs number of cols, so the resulting
|
|
// size would be the number of lhs rows.
|
|
int dstVecLen = lhsRows;
|
|
dstType = GetBaseTypeWithDims(dstBase, 1, dstVecLen);
|
|
}
|
|
else if (isRhsMatrix)
|
|
{
|
|
HlslUtil.ParserAssert(!isLhsMatrix); // should be handled by case above
|
|
// we'll assume that the rhs number of rows is the same as the lhs number of cols, so the resulting
|
|
// size would be the number of rhs cols.
|
|
int dstVecLen = rhsCols;
|
|
dstType = GetBaseTypeWithDims(dstBase, 1, dstVecLen);
|
|
}
|
|
else
|
|
{
|
|
// neither is a matrix
|
|
HlslUtil.ParserAssert(!isLhsMatrix);
|
|
HlslUtil.ParserAssert(!isRhsMatrix);
|
|
|
|
int dstVecLen = -1;
|
|
|
|
if (lhsCols == 1 || rhsCols == 1)
|
|
{
|
|
// If one is a sclara and the other is a vector, then promote to a vector
|
|
dstVecLen = Math.Max(lhsCols, rhsCols);
|
|
}
|
|
else
|
|
{
|
|
// Was unsure if we should use the min or max type, but it seems that hlsl defaults to smaller type.
|
|
// void Unity_GradientNoise_LegacyMod_float (float2 UV, float3 Scale, out float Out)
|
|
//{
|
|
// float2 p = UV * Scale;
|
|
//
|
|
//
|
|
dstVecLen = Math.Min(lhsCols, rhsCols);
|
|
}
|
|
dstType = GetBaseTypeWithDims(dstBase, 1, dstVecLen);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For non-mul ops, just expand to the higher size. It's more permissive than the compiler, which should be fine.
|
|
int dstRows = Math.Max(lhsRows, rhsRows);
|
|
int dstCols = Math.Max(lhsCols, rhsCols);
|
|
dstType = GetBaseTypeWithDims(dstBase, dstRows, dstCols);
|
|
}
|
|
return dstType;
|
|
}
|
|
|
|
// returns -1 if invalid
|
|
static internal int GetSwizzleIndex(char ch)
|
|
{
|
|
int ret = -1;
|
|
switch (ch)
|
|
{
|
|
case 'x':
|
|
case 'r':
|
|
ret = 0;
|
|
break;
|
|
case 'y':
|
|
case 'g':
|
|
ret = 1;
|
|
break;
|
|
case 'z':
|
|
case 'b':
|
|
ret = 2;
|
|
break;
|
|
case 'w':
|
|
case 'a':
|
|
ret = 3;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// returns -1 if invalid
|
|
static internal int GetSwizzleLength(string swizzle, HlslNativeType nativeType)
|
|
{
|
|
// todo: verify that the swizzle
|
|
int numRows = GetNumRows(nativeType);
|
|
int numCols = GetNumCols(nativeType);
|
|
bool valid = true;
|
|
if (numRows != 1)
|
|
{
|
|
valid = false;
|
|
}
|
|
if (swizzle.Length == 0 || swizzle.Length > 4)
|
|
{
|
|
valid = false;
|
|
}
|
|
for (int i = 0; i < swizzle.Length; i++)
|
|
{
|
|
int val = GetSwizzleIndex(swizzle[i]);
|
|
if (val < 0 || val >= numCols)
|
|
{
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
return valid ? swizzle.Length : -1;
|
|
}
|
|
|
|
internal static string GetNativeTypeString(HlslNativeType type)
|
|
{
|
|
// skip the _
|
|
return type.ToString().Substring(1);
|
|
}
|
|
|
|
internal static string GetNativeTypeStringApd(HlslNativeType type)
|
|
{
|
|
string ret = "";
|
|
switch (type)
|
|
{
|
|
case HlslNativeType._float:
|
|
case HlslNativeType._float1:
|
|
ret = "FloatApd";
|
|
break;
|
|
case HlslNativeType._float2:
|
|
ret = "FloatApd2";
|
|
break;
|
|
case HlslNativeType._float3:
|
|
ret = "FloatApd3";
|
|
break;
|
|
case HlslNativeType._float4:
|
|
ret = "FloatApd4";
|
|
break;
|
|
case HlslNativeType._half:
|
|
case HlslNativeType._half1:
|
|
ret = "HalfApd";
|
|
break;
|
|
case HlslNativeType._half2:
|
|
ret = "HalfApd2";
|
|
break;
|
|
case HlslNativeType._half3:
|
|
ret = "HalfApd3";
|
|
break;
|
|
case HlslNativeType._half4:
|
|
ret = "HalfApd4";
|
|
break;
|
|
default:
|
|
HlslUtil.ParserAssert(false);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
internal struct PrototypeInfo
|
|
{
|
|
internal static PrototypeInfo MakePrototypeInfo(HlslParser.TypeInfo returnType, string identifier, HlslParser.TypeInfo[] paramInfoVec, int uniqueId)
|
|
{
|
|
PrototypeInfo ret = new PrototypeInfo();
|
|
ret.returnType = returnType;
|
|
ret.identifier = identifier;
|
|
ret.paramInfoVec = paramInfoVec;
|
|
ret.uniqueId = uniqueId;
|
|
return ret;
|
|
}
|
|
|
|
// return type
|
|
internal HlslParser.TypeInfo returnType;
|
|
|
|
// name of the function
|
|
internal string identifier;
|
|
|
|
// parameters
|
|
internal HlslParser.TypeInfo[] paramInfoVec;
|
|
|
|
internal int uniqueId;
|
|
}
|
|
|
|
internal struct OverloadInfo
|
|
{
|
|
// name of the identifier
|
|
internal string identifier;
|
|
|
|
// list of all functions that havet he same struct/identifer pair but differnt overloads
|
|
internal List<int> prototypeList;
|
|
}
|
|
|
|
// TODO: Replace the hash function
|
|
struct StringPair
|
|
{
|
|
string lhs;
|
|
string rhs;
|
|
}
|
|
|
|
// give then struct and identifier, get the index into the overloads
|
|
Dictionary<StringPair, int> overloadInfoFromStructFuncPair;
|
|
|
|
internal struct FieldInfo
|
|
{
|
|
internal string identifier;
|
|
|
|
internal int arrayDims;
|
|
internal HlslParser.TypeInfo typeInfo;
|
|
|
|
internal string[] semantics; // do we need semantics for builtin types?
|
|
|
|
// to avoid allocating an array for every single parameter, we can reuse these one for all non-array variables
|
|
//static int[] emptyDims = new int[0];
|
|
static string[] emptySemantics = new string[0];
|
|
|
|
static internal FieldInfo MakeNativeType(HlslNativeType nativeType, string fieldName, int dims, ApdAllowedState allowedState)
|
|
{
|
|
FieldInfo ret = new FieldInfo();
|
|
ret.identifier = fieldName;
|
|
ret.typeInfo = HlslParser.TypeInfo.MakeNativeType(nativeType, dims, allowedState);
|
|
ret.semantics = emptySemantics;
|
|
return ret;
|
|
}
|
|
|
|
static internal FieldInfo MakeStruct(string structName, string fieldName, int dims)
|
|
{
|
|
FieldInfo ret = new FieldInfo();
|
|
ret.identifier = fieldName;
|
|
ret.typeInfo = HlslParser.TypeInfo.MakeStruct(structName, dims);
|
|
ret.semantics = emptySemantics;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
internal struct StructInfo
|
|
{
|
|
internal string identifier;
|
|
|
|
internal FieldInfo[] fields;
|
|
internal PrototypeInfo[] prototypes;
|
|
|
|
}
|
|
|
|
// maintains all the information for parsed structs and prototypes
|
|
internal class ParsedFuncStructData
|
|
{
|
|
internal List<HlslUtil.PrototypeInfo> allPrototypes;
|
|
|
|
// for each identifier, a list of all the prototypes that overload can have
|
|
internal List<HlslUtil.OverloadInfo> allOverloads;
|
|
|
|
// for each unique identifier, the index of allOverload.
|
|
internal Dictionary<string, int> overloadFromIdentifer;
|
|
|
|
// for each custom struct, our description of it
|
|
internal List<HlslUtil.StructInfo> allStructs;
|
|
|
|
// for each unique identifier, the index of allStructs
|
|
internal Dictionary<string, int> structFromIdentifer;
|
|
|
|
|
|
internal ParsedFuncStructData()
|
|
{
|
|
allPrototypes = new List<HlslUtil.PrototypeInfo>();
|
|
allOverloads = new List<HlslUtil.OverloadInfo>();
|
|
overloadFromIdentifer = new Dictionary<string, int>();
|
|
|
|
// for each custom struct, our description of it
|
|
allStructs = new List<HlslUtil.StructInfo>();
|
|
|
|
// for each unique identifier, the index of allStructs
|
|
structFromIdentifer = new Dictionary<string, int>();
|
|
}
|
|
|
|
internal void AddStruct(HlslUtil.StructInfo structInfo)
|
|
{
|
|
int dstIndex = allStructs.Count;
|
|
allStructs.Add(structInfo);
|
|
|
|
structFromIdentifer.Add(structInfo.identifier, dstIndex);
|
|
}
|
|
|
|
internal int AddPrototype(HlslUtil.PrototypeInfo protoInfo)
|
|
{
|
|
int dstProtoIndex = allPrototypes.Count;
|
|
allPrototypes.Add(protoInfo);
|
|
|
|
int foundOverloadIndex = -1;
|
|
if (overloadFromIdentifer.ContainsKey(protoInfo.identifier))
|
|
{
|
|
foundOverloadIndex = overloadFromIdentifer[protoInfo.identifier];
|
|
}
|
|
else
|
|
{
|
|
foundOverloadIndex = allOverloads.Count;
|
|
|
|
HlslUtil.OverloadInfo overloadInfo = new HlslUtil.OverloadInfo();
|
|
overloadInfo.identifier = protoInfo.identifier;
|
|
overloadInfo.prototypeList = new List<int>();
|
|
|
|
allOverloads.Add(overloadInfo);
|
|
|
|
overloadFromIdentifer.Add(protoInfo.identifier, foundOverloadIndex);
|
|
}
|
|
|
|
allOverloads[foundOverloadIndex].prototypeList.Add(dstProtoIndex);
|
|
|
|
return dstProtoIndex;
|
|
}
|
|
|
|
}
|
|
|
|
internal static void ParserAssert(bool condition)
|
|
{
|
|
// note that we are doing the if(!condition) so that we have a place to set a breakpoint
|
|
if (!condition)
|
|
{
|
|
Assert.IsTrue(condition);
|
|
}
|
|
}
|
|
}
|
|
}
|