HLSL: Add SampleCmp and SampleCmpLevelZero texture methods

This commit is contained in:
LoopDawg
2016-07-19 14:28:05 -06:00
parent 934855a642
commit a78b02941b
21 changed files with 5143 additions and 49 deletions

View File

@@ -661,8 +661,11 @@ bool HlslGrammar::acceptSamplerType(TType& type)
// read sampler type
const EHlslTokenClass samplerType = peek();
// TODO: for DX9
// TSamplerDim dim = EsdNone;
bool isShadow = false;
switch (samplerType) {
case EHTokSampler: break;
case EHTokSampler1d: /*dim = Esd1D*/; break;
@@ -670,7 +673,7 @@ bool HlslGrammar::acceptSamplerType(TType& type)
case EHTokSampler3d: /*dim = Esd3D*/; break;
case EHTokSamplerCube: /*dim = EsdCube*/; break;
case EHTokSamplerState: break;
case EHTokSamplerComparisonState: break;
case EHTokSamplerComparisonState: isShadow = true; break;
default:
return false; // not a sampler declaration
}
@@ -678,10 +681,9 @@ bool HlslGrammar::acceptSamplerType(TType& type)
advanceToken(); // consume the sampler type keyword
TArraySizes* arraySizes = nullptr; // TODO: array
bool shadow = false; // TODO: shadow
TSampler sampler;
sampler.setPureSampler(shadow);
sampler.setPureSampler(isShadow);
type.shallowCopy(TType(sampler, EvqUniform, arraySizes));

View File

@@ -825,6 +825,7 @@ TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc
TSampler samplerType = argTex->getType().getSampler();
samplerType.combined = true;
samplerType.shadow = argSampler->getType().getSampler().shadow;
txcombine->setType(TType(samplerType, EvqTemporary));
txcombine->setLoc(loc);
@@ -1063,6 +1064,66 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
break;
}
case EOpMethodSampleCmp: // fall through...
case EOpMethodSampleCmpLevelZero:
{
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped();
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
TIntermTyped* argCmpVal = argAggregate->getSequence()[3]->getAsTyped();
TIntermTyped* argOffset = nullptr;
// optional offset value
if (argAggregate->getSequence().size() > 4)
argOffset = argAggregate->getSequence()[4]->getAsTyped();
const int coordDimWithCmpVal = argCoord->getType().getVectorSize() + 1; // +1 for cmp
// AST wants comparison value as one of the texture coordinates
TOperator constructOp = EOpNull;
switch (coordDimWithCmpVal) {
// 1D can't happen: there's always at least 1 coordinate dimension + 1 cmp val
case 2: constructOp = EOpConstructVec2; break;
case 3: constructOp = EOpConstructVec3; break;
case 4: constructOp = EOpConstructVec4; break;
case 5: constructOp = EOpConstructVec4; break; // cubeArrayShadow, cmp value is separate arg.
default: assert(0); break;
}
TIntermAggregate* coordWithCmp = new TIntermAggregate(constructOp);
coordWithCmp->getSequence().push_back(argCoord);
if (coordDimWithCmpVal != 5) // cube array shadow is special.
coordWithCmp->getSequence().push_back(argCmpVal);
coordWithCmp->setLoc(loc);
TOperator textureOp = (op == EOpMethodSampleCmpLevelZero ? EOpTextureLod : EOpTexture);
if (argOffset != nullptr)
textureOp = (op == EOpMethodSampleCmpLevelZero ? EOpTextureLodOffset : EOpTextureOffset);
// Create combined sampler & texture op
TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp);
TIntermAggregate* txsample = new TIntermAggregate(textureOp);
txsample->getSequence().push_back(txcombine);
txsample->getSequence().push_back(coordWithCmp);
if (coordDimWithCmpVal == 5) // cube array shadow is special: cmp val follows coord.
txsample->getSequence().push_back(argCmpVal);
// the LevelZero form uses 0 as an explicit LOD
if (op == EOpMethodSampleCmpLevelZero)
txsample->getSequence().push_back(intermediate.addConstantUnion(0.0, EbtFloat, loc, true));
// Add offset if present
if (argOffset != nullptr)
txsample->getSequence().push_back(argOffset);
txsample->setType(node->getType());
txsample->setLoc(loc);
node = txsample;
break;
}
default:
break; // most pass through unchanged
}

View File

@@ -69,7 +69,7 @@ const char* BaseTypeName(const char argOrder, const char* scalarName, const char
bool IsTextureType(const char argOrder) { return argOrder == '%' || argOrder == '@'; }
bool IsTextureArrayed(const char argOrder) { return argOrder == '@'; }
bool IsTextureMS(const char /*argOrder*/) { return false; } // TODO: ...
bool IsTextureMS(const char /*argOrder*/) { return false; } // TODO: ...
// Reject certain combinations that are illegal sample methods. For example,
// 3D arrays.
@@ -78,33 +78,47 @@ bool IsIllegalSample(const glslang::TString& name, const char* argOrder, int dim
const bool isArrayed = IsTextureArrayed(*argOrder);
const bool isMS = IsTextureMS(*argOrder);
// there are no 3D arrayed textures, or 3D SampleCmp
if (dim0 == 3 && (isArrayed || name == "SampleCmp"))
// there are no 3D arrayed textures, or 3D SampleCmp(LevelZero)
if (dim0 == 3 && (isArrayed || name == "SampleCmp" || name == "SampleCmpLevelZero"))
return true;
const int numArgs = int(std::count(argOrder, argOrder + strlen(argOrder), ',')) + 1;
// Reject invalid offset arrayed forms with cubemaps
if (isArrayed && dim0 == 4) {
// Reject invalid offset forms with cubemaps
if (dim0 == 4) {
if ((name == "Sample" && numArgs >= 4) ||
(name == "SampleBias" && numArgs >= 5) ||
(name == "SampleCmp" && numArgs >= 5) ||
(name == "SampleCmpLevelZero" && numArgs >= 4) ||
(name == "SampleCmpLevelZero" && numArgs >= 5) ||
(name == "SampleGrad" && numArgs >= 6) ||
(name == "SampleLevel" && numArgs >= 5))
return true;
}
// Reject invalid Loads
if (name == "Load") {
if ((numArgs >= 3 && !isMS) || // Load with sampleindex requires multisample
(dim0 == 4)) // Load does not support any cubemaps, arrayed or not.
return true;
}
if (name == "Load" && dim0 == 4)
return true; // Load does not support any cubemaps, arrayed or not.
return false;
}
// Return the number of the coordinate arg, if any
int CoordinateArgPos(const glslang::TString& name, bool isTexture)
{
if (!isTexture || (name == "GetDimensions"))
return -1; // has none
else if (name == "Load")
return 1;
else
return 2; // other texture methods are 2
}
// Some texture methods use an addition coordinate dimension for the mip
bool HasMipInCoord(const glslang::TString& name)
{
return name == "Load";
}
// Create and return a type name. This is done in GLSL, not HLSL conventions, until such
// time as builtins are parsed using the HLSL parser.
//
@@ -141,17 +155,18 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
if (UseHlslTypes) {
switch (type) {
case '-': s += "void"; break;
case 'F': s += "float"; break;
case 'D': s += "double"; break;
case 'I': s += "int"; break;
case 'U': s += "uint"; break;
case 'B': s += "bool"; break;
case 'S': s += "sampler"; break;
case 'T': s += "Texture"; break;
case 'i': s += "Texture <int4>"; break;
case 'u': s += "Texture <uint4>"; break;
default: s += "UNKNOWN_TYPE"; break;
case '-': s += "void"; break;
case 'F': s += "float"; break;
case 'D': s += "double"; break;
case 'I': s += "int"; break;
case 'U': s += "uint"; break;
case 'B': s += "bool"; break;
case 'S': s += "sampler"; break;
case 's': s += "SamplerComparisonState"; break;
case 'T': s += "Texture"; break;
case 'i': s += "Texture <int4>"; break;
case 'u': s += "Texture <uint4>"; break;
default: s += "UNKNOWN_TYPE"; break;
}
} else {
switch (type) {
@@ -162,6 +177,7 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
case 'U': s += BaseTypeName(order, "uint", "uvec", "umat"); break;
case 'B': s += BaseTypeName(order, "bool", "bvec", "bmat"); break;
case 'S': s += "sampler"; break;
case 's': s += "samplerShadow"; break;
case 'T': // fall through
case 'i': // ...
case 'u': // ...
@@ -369,7 +385,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
// orderKey can be:
// S = scalar, V = vector, M = matrix, - = void
// typekey can be:
// D = double, F = float, U = uint, I = int, B = bool, S = sampler
// D = double, F = float, U = uint, I = int, B = bool, S = sampler, s = shadowSampler
// An empty order or type key repeats the first one. E.g: SVM,, means 3 args each of SVM.
// '>' as first letter of order creates an output parameter
// '<' as first letter of order creates an input parameter
@@ -555,33 +571,35 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
{ "SampleBias", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask },
{ "SampleBias", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask },
// { "SampleCmp", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangFragmentMask },
// { "SampleCmp", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask },
// { "SampleCmp", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask },
// { "SampleCmp", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask },
// TODO: FXC accepts int/uint samplers here. unclear what that means.
{ "SampleCmp", /*!O !A*/ "S", "F", "%V,S,V,S", "FIU,s,F,F", EShLangFragmentMask },
{ "SampleCmp", /* O !A*/ "S", "F", "%V,S,V,S,V", "FIU,s,F,F,I", EShLangFragmentMask },
{ "SampleCmp", /*!O A*/ "S", "F", "@V,S,V,S", "FIU,s,F,F", EShLangFragmentMask },
{ "SampleCmp", /* O A*/ "S", "F", "@V,S,V,S,V", "FIU,s,F,F,I", EShLangFragmentMask },
// { "SampleCmpLevelZero", /*!O !A*/ "V4", nullptr, "%V,S,V", "FIU,S,F", EShLangFragmentMask },
// { "SampleCmpLevelZero", /* O !A*/ "V4", nullptr, "%V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
// { "SampleCmpLevelZero", /*!O A*/ "V4", nullptr, "@V,S,V", "FIU,S,F", EShLangFragmentMask },
// { "SampleCmpLevelZero", /* O A*/ "V4", nullptr, "@V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
// TODO: FXC accepts int/uint samplers here. unclear what that means.
{ "SampleCmpLevelZero", /*!O !A*/ "S", "F", "%V,S,V,S", "FIU,s,F,F", EShLangFragmentMask },
{ "SampleCmpLevelZero", /* O !A*/ "S", "F", "%V,S,V,S,V", "FIU,s,F,F,I", EShLangFragmentMask },
{ "SampleCmpLevelZero", /*!O A*/ "S", "F", "@V,S,V,S", "FIU,s,F,F", EShLangFragmentMask },
{ "SampleCmpLevelZero", /* O A*/ "S", "F", "@V,S,V,S,V", "FIU,s,F,F,I", EShLangFragmentMask },
{ "SampleGrad", /*!O !A*/ "V4", nullptr, "%V,S,V,V,V", "FIU,S,F,F,F", EShLangAll },
{ "SampleGrad", /* O !A*/ "V4", nullptr, "%V,S,V,V,V,V", "FIU,S,F,F,F,I", EShLangAll },
{ "SampleGrad", /*!O A*/ "V4", nullptr, "@V,S,V,V,V", "FIU,S,F,F,F", EShLangAll },
{ "SampleGrad", /* O A*/ "V4", nullptr, "@V,S,V,V,V,V", "FIU,S,F,F,F,I", EShLangAll },
// { "SampleLevel", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangFragmentMask },
// { "SampleLevel", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask },
// { "SampleLevel", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangFragmentMask },
// { "SampleLevel", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangFragmentMask },
// { "SampleLevel", /*!O !A*/ "V4", nullptr, "%V,S,V,S", "FIU,S,F,F", EShLangAll },
// { "SampleLevel", /* O !A*/ "V4", nullptr, "%V,S,V,S,V", "FIU,S,F,F,I", EShLangAll },
// { "SampleLevel", /*!O A*/ "V4", nullptr, "@V,S,V,S", "FIU,S,F,F", EShLangAll },
// { "SampleLevel", /* O A*/ "V4", nullptr, "@V,S,V,S,V", "FIU,S,F,F,I", EShLangAll },
// TODO: ...
// { "Load", "V4", nullptr, "%V,V", "FIU,I", EShLangFragmentMask },
// { "Load", /* +sampleidex*/ "V4", nullptr, "%V,V,S", "FIU,I,I", EShLangFragmentMask },
// { "Load", /* +samplindex, offset*/ "V4", nullptr, "%V,V,S,V", "FIU,I,I,I", EShLangFragmentMask },
// { "Load", "V4", nullptr, "@V,V", "FIU,I", EShLangFragmentMask },
// { "Load", /* +sampleidex*/ "V4", nullptr, "@V,V,S", "FIU,I,I", EShLangFragmentMask },
// { "Load", /* +samplindex, offset*/ "V4", nullptr, "@V,V,S,V", "FIU,I,I,I", EShLangFragmentMask },
// { "Load", "V4", nullptr, "%V,V", "FIU,I", EShLangAll },
// { "Load", "V4", nullptr, "@V,V", "FIU,I", EShLangAll },
// { "Load", /* offset*/ "V4", nullptr, "%V,V,V", "FIU,I,I", EShLangAll },
// { "Load", /* offset*/ "V4", nullptr, "@V,V,V", "FIU,I,I", EShLangAll },
// TODO: MS variants of Load
// { "Load", /* +sampleidex*/ "V4", nullptr, "$V,V,S", "FIU,I,I", EShLangAll },
// { "Load", /* +samplindex, offset*/ "V4", nullptr, "$V,V,S,V", "FIU,I,I,I", EShLangAll },
// table of overloads from: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509693(v=vs.85).aspx
//
@@ -660,7 +678,9 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
for (const char* argOrder = intrinsic.argOrder; !IsEndOfArg(argOrder); ++argOrder) { // for each order...
const bool isTexture = IsTextureType(*argOrder);
const bool isArrayed = IsTextureArrayed(*argOrder);
const bool mipInCoord = HasMipInCoord(intrinsic.name);
const int fixedVecSize = FixedVecSize(argOrder);
const int coordArg = CoordinateArgPos(intrinsic.name, isTexture);
// calculate min and max vector and matrix dimensions
int dim0Min = 1;
@@ -701,7 +721,11 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
int argDim0 = isTexture && arg > 0 ? std::min(dim0, 3) : dim0;
// arrayed textures have one extra coordinate dimension
if (isArrayed && arg == 2)
if (isArrayed && arg == coordArg)
argDim0++;
// Some texture methods use an addition arg dimension to hold mip
if (arg == coordArg && mipInCoord)
argDim0++;
// For textures, the 1D case isn't a 1-vector, but a scalar.
@@ -916,8 +940,8 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
// Texture methods
symbolTable.relateToOperator("Sample", EOpMethodSample);
symbolTable.relateToOperator("SampleBias", EOpMethodSampleBias);
// symbolTable.relateToOperator("SampleCmp", EOpMethodSampleCmp);
// symbolTable.relateToOperator("SampleCmpLevelZero", EOpMethodSampleCmpLevelZero);
symbolTable.relateToOperator("SampleCmp", EOpMethodSampleCmp);
symbolTable.relateToOperator("SampleCmpLevelZero", EOpMethodSampleCmpLevelZero);
symbolTable.relateToOperator("SampleGrad", EOpMethodSampleGrad);
// symbolTable.relateToOperator("SampleLevel", EOpMethodSampleLevel);
// symbolTable.relateToOperator("Load", EOpMethodLoad);