HLSL: Add GatherRed/Green/Blue/Alpha methods, inc 4-offset forms
This commit is contained in:
@@ -581,6 +581,15 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
|
||||
} else if (field == "CalculateLevelOfDetail" ||
|
||||
field == "CalculateLevelOfDetailUnclamped" ||
|
||||
field == "Gather" ||
|
||||
field == "GatherRed" ||
|
||||
field == "GatherGreen" ||
|
||||
field == "GatherBlue" ||
|
||||
field == "GatherAlpha" ||
|
||||
field == "GatherCmp" ||
|
||||
field == "GatherCmpRed" ||
|
||||
field == "GatherCmpGreen" ||
|
||||
field == "GatherCmpBlue" ||
|
||||
field == "GatherCmpAlpha" ||
|
||||
field == "GetDimensions" ||
|
||||
field == "GetSamplePosition" ||
|
||||
field == "Load" ||
|
||||
@@ -1251,7 +1260,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
TIntermTyped* argOffset = nullptr;
|
||||
|
||||
// Offset is optional
|
||||
if (argAggregate->getSequence().size() == 4)
|
||||
if (argAggregate->getSequence().size() > 3)
|
||||
argOffset = argAggregate->getSequence()[3]->getAsTyped();
|
||||
|
||||
const TOperator textureOp = (argOffset == nullptr ? EOpTextureGather : EOpTextureGatherOffset);
|
||||
@@ -1261,6 +1270,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
|
||||
txgather->getSequence().push_back(txcombine);
|
||||
txgather->getSequence().push_back(argCoord);
|
||||
// Offset if not given is implicitly channel 0 (red)
|
||||
|
||||
if (argOffset != nullptr)
|
||||
txgather->getSequence().push_back(argOffset);
|
||||
@@ -1272,6 +1282,131 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
break;
|
||||
}
|
||||
|
||||
case EOpMethodGatherRed: // fall through...
|
||||
case EOpMethodGatherGreen: // ...
|
||||
case EOpMethodGatherBlue: // ...
|
||||
case EOpMethodGatherAlpha: // ...
|
||||
case EOpMethodGatherCmpRed: // ...
|
||||
case EOpMethodGatherCmpGreen: // ...
|
||||
case EOpMethodGatherCmpBlue: // ...
|
||||
case EOpMethodGatherCmpAlpha: // ...
|
||||
{
|
||||
int channel = 0; // the channel we are gathering
|
||||
int cmpValues = 0; // 1 if there is a compare value (handier than a bool below)
|
||||
|
||||
switch (op) {
|
||||
case EOpMethodGatherCmpRed: cmpValues = 1; // fall through
|
||||
case EOpMethodGatherRed: channel = 0; break;
|
||||
case EOpMethodGatherCmpGreen: cmpValues = 1; // fall through
|
||||
case EOpMethodGatherGreen: channel = 1; break;
|
||||
case EOpMethodGatherCmpBlue: cmpValues = 1; // fall through
|
||||
case EOpMethodGatherBlue: channel = 2; break;
|
||||
case EOpMethodGatherCmpAlpha: cmpValues = 1; // fall through
|
||||
case EOpMethodGatherAlpha: channel = 3; break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
// For now, we have nothing to map the component-wise comparison forms
|
||||
// to, because neither GLSL nor SPIR-V has such an opcode. Issue an
|
||||
// unimplemented error instead. Most of the machinery is here if that
|
||||
// should ever become available.
|
||||
if (cmpValues) {
|
||||
error(loc, "unimplemented: component-level gather compare", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
int arg = 0;
|
||||
|
||||
TIntermTyped* argTex = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
TIntermTyped* argSamp = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
TIntermTyped* argCoord = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
TIntermTyped* argOffset = nullptr;
|
||||
TIntermTyped* argOffsets[4] = { nullptr, nullptr, nullptr, nullptr };
|
||||
// TIntermTyped* argStatus = nullptr; // TODO: residency
|
||||
TIntermTyped* argCmp = nullptr;
|
||||
|
||||
const TSamplerDim dim = argTex->getType().getSampler().dim;
|
||||
|
||||
const int argSize = argAggregate->getSequence().size();
|
||||
bool hasStatus = (argSize == (5+cmpValues) || argSize == (8+cmpValues));
|
||||
bool hasOffset1 = false;
|
||||
bool hasOffset4 = false;
|
||||
|
||||
// Only 2D forms can have offsets. Discover if we have 0, 1 or 4 offsets.
|
||||
if (dim == Esd2D) {
|
||||
hasOffset1 = (argSize == (4+cmpValues) || argSize == (5+cmpValues));
|
||||
hasOffset4 = (argSize == (7+cmpValues) || argSize == (8+cmpValues));
|
||||
}
|
||||
|
||||
assert(!(hasOffset1 && hasOffset4));
|
||||
|
||||
TOperator textureOp = EOpTextureGather;
|
||||
|
||||
// Compare forms have compare value
|
||||
if (cmpValues != 0)
|
||||
argCmp = argOffset = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
|
||||
// Some forms have single offset
|
||||
if (hasOffset1) {
|
||||
textureOp = EOpTextureGatherOffset; // single offset form
|
||||
argOffset = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
}
|
||||
|
||||
// Some forms have 4 gather offsets
|
||||
if (hasOffset4) {
|
||||
textureOp = EOpTextureGatherOffsets; // note plural, for 4 offset form
|
||||
for (int offsetNum = 0; offsetNum < 4; ++offsetNum)
|
||||
argOffsets[offsetNum] = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
}
|
||||
|
||||
// Residency status
|
||||
if (hasStatus) {
|
||||
// argStatus = argAggregate->getSequence()[arg++]->getAsTyped();
|
||||
error(loc, "unimplemented: residency status", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
TIntermAggregate* txgather = new TIntermAggregate(textureOp);
|
||||
TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp);
|
||||
|
||||
TIntermTyped* argChannel = intermediate.addConstantUnion(channel, loc, true);
|
||||
|
||||
txgather->getSequence().push_back(txcombine);
|
||||
txgather->getSequence().push_back(argCoord);
|
||||
|
||||
// AST wants an array of 4 offsets, where HLSL has separate args. Here
|
||||
// we construct an array from the separate args.
|
||||
if (hasOffset4) {
|
||||
TType arrayType(EbtInt, EvqTemporary, 2);
|
||||
TArraySizes arraySizes;
|
||||
arraySizes.addInnerSize(4);
|
||||
arrayType.newArraySizes(arraySizes);
|
||||
|
||||
TIntermAggregate* initList = new TIntermAggregate(EOpNull);
|
||||
|
||||
for (int offsetNum = 0; offsetNum < 4; ++offsetNum)
|
||||
initList->getSequence().push_back(argOffsets[offsetNum]);
|
||||
|
||||
argOffset = addConstructor(loc, initList, arrayType);
|
||||
}
|
||||
|
||||
// Add comparison value if we have one
|
||||
if (argTex->getType().getSampler().isShadow())
|
||||
txgather->getSequence().push_back(argCmp);
|
||||
|
||||
// Add offset (either 1, or an array of 4) if we have one
|
||||
if (argOffset != nullptr)
|
||||
txgather->getSequence().push_back(argOffset);
|
||||
|
||||
txgather->getSequence().push_back(argChannel);
|
||||
|
||||
txgather->setType(node->getType());
|
||||
txgather->setLoc(loc);
|
||||
node = txgather;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EOpMethodCalculateLevelOfDetail:
|
||||
case EOpMethodCalculateLevelOfDetailUnclamped:
|
||||
{
|
||||
|
||||
@@ -101,12 +101,29 @@ bool IsIllegalSample(const glslang::TString& name, const char* argOrder, int dim
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool isGather =
|
||||
(name == "Gather" ||
|
||||
name == "GatherRed" ||
|
||||
name == "GatherGreen" ||
|
||||
name == "GatherBlue" ||
|
||||
name == "GatherAlpha");
|
||||
|
||||
const bool isGatherCmp =
|
||||
(name == "GatherCmpRed" ||
|
||||
name == "GatherCmpGreen" ||
|
||||
name == "GatherCmpBlue" ||
|
||||
name == "GatherCmpAlpha");
|
||||
|
||||
// Reject invalid Gathers
|
||||
if (name == "Gather") {
|
||||
if (isGather || isGatherCmp) {
|
||||
if (dim0 == 1 || dim0 == 3) // there are no 1D or 3D gathers
|
||||
return true;
|
||||
if (dim0 == 4 && numArgs == 4) // there are no Cube gathers with offset
|
||||
return true;
|
||||
|
||||
// no offset on cube or cube array gathers
|
||||
if (dim0 == 4) {
|
||||
if ((isGather && numArgs > 3) || (isGatherCmp && numArgs > 4))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Reject invalid Loads
|
||||
@@ -648,15 +665,14 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
{ "Load", /* +sampleidex*/ "V4", nullptr, "$&,V,S", "FIU,I,I", EShLangAll },
|
||||
{ "Load", /* +samplindex, offset*/ "V4", nullptr, "$&,V,S,V", "FIU,I,I,I", EShLangAll },
|
||||
|
||||
{ "Gather", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangVSPSGS },
|
||||
{ "Gather", /* O*/ "V4", nullptr, "%@,S,V,V", "FIU,S,F,I", EShLangVSPSGS },
|
||||
{ "Gather", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
|
||||
{ "Gather", /* O*/ "V4", nullptr, "%@,S,V,V", "FIU,S,F,I", EShLangAll },
|
||||
|
||||
{ "CalculateLevelOfDetail", "S", "F", "%@,S,V", "FUI,S,F", EShLangFragmentMask },
|
||||
{ "CalculateLevelOfDetailUnclamped", "S", "F", "%@,S,V", "FUI,S,F", EShLangFragmentMask },
|
||||
|
||||
{ "GetSamplePosition", "V2", "F", "$&2,S", "FUI,I", EShLangVSPSGS },
|
||||
|
||||
// table of overloads from: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509693(v=vs.85).aspx
|
||||
//
|
||||
// UINT Width
|
||||
// UINT MipLevel, UINT Width, UINT NumberOfLevels
|
||||
@@ -709,10 +725,61 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
|
||||
// UINT Width, UINT Height, UINT Samples
|
||||
// UINT Width, UINT Height, UINT Elements, UINT Samples
|
||||
{ "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMS */ "-", "-", "$2,>S,,", "FUI,U,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll },
|
||||
{ "GetDimensions", /* 2DMSArray */ "-", "-", "&2,>S,,,", "FUI,U,,,", EShLangAll },
|
||||
|
||||
// SM5 texture methods
|
||||
{ "GatherRed", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
|
||||
{ "GatherRed", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll },
|
||||
{ "GatherRed", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll },
|
||||
{ "GatherRed", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll },
|
||||
{ "GatherRed", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherGreen", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
|
||||
{ "GatherGreen", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll },
|
||||
{ "GatherGreen", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll },
|
||||
{ "GatherGreen", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll },
|
||||
{ "GatherGreen", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherBlue", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
|
||||
{ "GatherBlue", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll },
|
||||
{ "GatherBlue", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll },
|
||||
{ "GatherBlue", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll },
|
||||
{ "GatherBlue", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherAlpha", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
|
||||
{ "GatherAlpha", /* O*/ "V4", nullptr, "%@,S,V,", "FIU,S,F,I", EShLangAll },
|
||||
{ "GatherAlpha", /* O, status*/ "V4", nullptr, "%@,S,V,,>S", "FIU,S,F,I,U", EShLangAll },
|
||||
{ "GatherAlpha", /* O-4 */ "V4", nullptr, "%@,S,V,,,,", "FIU,S,F,I,,,", EShLangAll },
|
||||
{ "GatherAlpha", /* O-4, status */"V4", nullptr, "%@,S,V,,,,,S", "FIU,S,F,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherCmpRed", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll },
|
||||
{ "GatherCmpRed", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll },
|
||||
{ "GatherCmpRed", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll },
|
||||
{ "GatherCmpRed", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll },
|
||||
{ "GatherCmpRed", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,V,S","FIU,s,F,,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherCmpGreen", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll },
|
||||
{ "GatherCmpGreen", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll },
|
||||
{ "GatherCmpGreen", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll },
|
||||
{ "GatherCmpGreen", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll },
|
||||
{ "GatherCmpGreen", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherCmpBlue", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll },
|
||||
{ "GatherCmpBlue", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll },
|
||||
{ "GatherCmpBlue", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll },
|
||||
{ "GatherCmpBlue", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll },
|
||||
{ "GatherCmpBlue", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll },
|
||||
|
||||
{ "GatherCmpAlpha", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,s,F,", EShLangAll },
|
||||
{ "GatherCmpAlpha", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,s,F,,I", EShLangAll },
|
||||
{ "GatherCmpAlpha", /* O, status*/ "V4", nullptr, "%@,S,V,S,V,>S", "FIU,s,F,,I,U", EShLangAll },
|
||||
{ "GatherCmpAlpha", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll },
|
||||
{ "GatherCmpAlpha", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll },
|
||||
|
||||
// TODO: Cmp forms
|
||||
|
||||
// Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
|
||||
{ nullptr, nullptr, nullptr, nullptr, nullptr, 0 },
|
||||
@@ -1012,6 +1079,16 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
|
||||
symbolTable.relateToOperator("Gather", EOpMethodGather);
|
||||
symbolTable.relateToOperator("CalculateLevelOfDetail", EOpMethodCalculateLevelOfDetail);
|
||||
symbolTable.relateToOperator("CalculateLevelOfDetailUnclamped", EOpMethodCalculateLevelOfDetailUnclamped);
|
||||
|
||||
// SM5 Texture methods
|
||||
symbolTable.relateToOperator("GatherRed", EOpMethodGatherRed);
|
||||
symbolTable.relateToOperator("GatherGreen", EOpMethodGatherGreen);
|
||||
symbolTable.relateToOperator("GatherBlue", EOpMethodGatherBlue);
|
||||
symbolTable.relateToOperator("GatherAlpha", EOpMethodGatherAlpha);
|
||||
symbolTable.relateToOperator("GatherCmpRed", EOpMethodGatherCmpRed);
|
||||
symbolTable.relateToOperator("GatherCmpGreen", EOpMethodGatherCmpGreen);
|
||||
symbolTable.relateToOperator("GatherCmpBlue", EOpMethodGatherCmpBlue);
|
||||
symbolTable.relateToOperator("GatherCmpAlpha", EOpMethodGatherCmpAlpha);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user