HLSL: Add SampleCmp and SampleCmpLevelZero texture methods
This commit is contained in:
@@ -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));
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user