HLSL: Add SampleBias and SampleGrad, and associated tests
This commit is contained in:
@@ -814,9 +814,28 @@ TOperator HlslParseContext::mapAtomicOp(const TSourceLoc& loc, TOperator op, boo
|
||||
}
|
||||
|
||||
//
|
||||
// Change texture parameters to match AST & SPIR-V semantics
|
||||
// Create a combined sampler/texture from separate sampler and texture.
|
||||
//
|
||||
void HlslParseContext::textureParameters(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
|
||||
TIntermAggregate* HlslParseContext::handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, TIntermTyped* argSampler)
|
||||
{
|
||||
TIntermAggregate* txcombine = new TIntermAggregate(EOpConstructTextureSampler);
|
||||
|
||||
txcombine->getSequence().push_back(argTex);
|
||||
txcombine->getSequence().push_back(argSampler);
|
||||
|
||||
TSampler samplerType = argTex->getType().getSampler();
|
||||
samplerType.combined = true;
|
||||
|
||||
txcombine->setType(TType(samplerType, EvqTemporary));
|
||||
txcombine->setLoc(loc);
|
||||
|
||||
return txcombine;
|
||||
}
|
||||
|
||||
//
|
||||
// Decompose DX9 and DX10 sample intrinsics & object methods into AST
|
||||
//
|
||||
void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
|
||||
{
|
||||
if (!node || !node->getAsOperator())
|
||||
return;
|
||||
@@ -825,9 +844,10 @@ void HlslParseContext::textureParameters(const TSourceLoc& loc, TIntermTyped*& n
|
||||
const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
|
||||
|
||||
switch (op) {
|
||||
// **** DX9 intrinsics: ****
|
||||
case EOpTexture:
|
||||
{
|
||||
// Texture with ddx & ddy is really gradient form
|
||||
// Texture with ddx & ddy is really gradient form in HLSL
|
||||
if (argAggregate->getSequence().size() == 4) {
|
||||
node->getAsAggregate()->setOperator(EOpTextureGrad);
|
||||
break;
|
||||
@@ -869,6 +889,81 @@ void HlslParseContext::textureParameters(const TSourceLoc& loc, TIntermTyped*& n
|
||||
break;
|
||||
}
|
||||
|
||||
// **** DX10 methods: ****
|
||||
case EOpMethodSample: // fall through
|
||||
case EOpMethodSampleBias: // ...
|
||||
{
|
||||
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped();
|
||||
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
|
||||
TIntermTyped* argBias = nullptr;
|
||||
TIntermTyped* argOffset = nullptr;
|
||||
|
||||
int nextArg = 3;
|
||||
|
||||
if (op == EOpMethodSampleBias) // SampleBias has a bias arg
|
||||
argBias = argAggregate->getSequence()[nextArg++]->getAsTyped();
|
||||
|
||||
TOperator textureOp = EOpTexture;
|
||||
|
||||
if (argAggregate->getSequence().size() == (nextArg+1)) { // last parameter is offset form
|
||||
textureOp = EOpTextureOffset;
|
||||
argOffset = argAggregate->getSequence()[nextArg++]->getAsTyped();
|
||||
}
|
||||
|
||||
TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp);
|
||||
|
||||
TIntermAggregate* txsample = new TIntermAggregate(textureOp);
|
||||
txsample->getSequence().push_back(txcombine);
|
||||
txsample->getSequence().push_back(argCoord);
|
||||
|
||||
if (argBias != nullptr)
|
||||
txsample->getSequence().push_back(argBias);
|
||||
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
|
||||
txsample->setType(node->getType());
|
||||
txsample->setLoc(loc);
|
||||
node = txsample;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EOpMethodSampleGrad: // ...
|
||||
{
|
||||
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped();
|
||||
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
|
||||
TIntermTyped* argDDX = argAggregate->getSequence()[3]->getAsTyped();
|
||||
TIntermTyped* argDDY = argAggregate->getSequence()[4]->getAsTyped();
|
||||
TIntermTyped* argOffset = nullptr;
|
||||
|
||||
TOperator textureOp = EOpTextureGrad;
|
||||
|
||||
if (argAggregate->getSequence().size() == 6) { // last parameter is offset form
|
||||
textureOp = EOpTextureGradOffset;
|
||||
argOffset = argAggregate->getSequence()[5]->getAsTyped();
|
||||
}
|
||||
|
||||
TIntermAggregate* txcombine = handleSamplerTextureCombine(loc, argTex, argSamp);
|
||||
|
||||
TIntermAggregate* txsample = new TIntermAggregate(textureOp);
|
||||
txsample->getSequence().push_back(txcombine);
|
||||
txsample->getSequence().push_back(argCoord);
|
||||
txsample->getSequence().push_back(argDDX);
|
||||
txsample->getSequence().push_back(argDDY);
|
||||
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
|
||||
txsample->setType(node->getType());
|
||||
txsample->setLoc(loc);
|
||||
node = txsample;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break; // most pass through unchanged
|
||||
}
|
||||
@@ -1222,59 +1317,6 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*&
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Decompose sample methods into AST
|
||||
//
|
||||
void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
|
||||
{
|
||||
if (!node || !node->getAsOperator())
|
||||
return;
|
||||
|
||||
const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
|
||||
const TOperator op = node->getAsOperator()->getOp();
|
||||
|
||||
switch (op) {
|
||||
case EOpMethodSample:
|
||||
{
|
||||
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped();
|
||||
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
|
||||
TIntermTyped* argOffset = nullptr;
|
||||
|
||||
TOperator textureOp = EOpTexture;
|
||||
|
||||
if (argAggregate->getSequence().size() == 4) { // 4th parameter is offset form
|
||||
textureOp = EOpTextureOffset;
|
||||
argOffset = argAggregate->getSequence()[3]->getAsTyped();
|
||||
}
|
||||
|
||||
TIntermAggregate* txcombine = new TIntermAggregate(EOpConstructTextureSampler);
|
||||
|
||||
txcombine->getSequence().push_back(argTex);
|
||||
txcombine->getSequence().push_back(argSamp);
|
||||
TSampler samplerType = argTex->getType().getSampler();
|
||||
samplerType.combined = true;
|
||||
txcombine->setType(TType(samplerType, EvqTemporary));
|
||||
txcombine->setLoc(loc);
|
||||
|
||||
TIntermAggregate* txsample = new TIntermAggregate(textureOp);
|
||||
txsample->getSequence().push_back(txcombine);
|
||||
txsample->getSequence().push_back(argCoord);
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
txsample->setType(node->getType());
|
||||
txsample->setLoc(loc);
|
||||
node = txsample;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break; // most pass through unchanged
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Handle seeing function call syntax in the grammar, which could be any of
|
||||
// - .length() method
|
||||
@@ -1380,7 +1422,6 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
|
||||
|
||||
decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
|
||||
decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions
|
||||
textureParameters(loc, result, arguments); // HLSL->AST texture intrinsics
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ public:
|
||||
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
void textureParameters(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
|
||||
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
|
||||
@@ -96,6 +95,8 @@ public:
|
||||
TFunction* handleConstructorCall(const TSourceLoc&, const TType&);
|
||||
void handleSemantic(TType& type, const TString& semantic);
|
||||
|
||||
TIntermAggregate* handleSamplerTextureCombine(const TSourceLoc& loc, TIntermTyped* argTex, TIntermTyped* argSampler);
|
||||
|
||||
bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&);
|
||||
void assignError(const TSourceLoc&, const char* op, TString left, TString right);
|
||||
void unaryOpError(const TSourceLoc&, const char* op, TString operand);
|
||||
|
||||
@@ -67,23 +67,38 @@ 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 IsTextureType(const char argOrder) { return argOrder == '%' || argOrder == '@'; }
|
||||
bool IsTextureArrayed(const char argOrder) { return argOrder == '@'; }
|
||||
bool IsTextureMS(const char argOrder) { return false; } // TODO: ...
|
||||
|
||||
// Reject certain combinations that are illegal sample methods. For example,
|
||||
// 3D arrays.
|
||||
bool IsIllegalSample(const glslang::TString& name, const char* argOrder, int dim0)
|
||||
{
|
||||
const bool isArrayed = IsTextureArrayed(*argOrder);
|
||||
const bool isMS = IsTextureMS(*argOrder);
|
||||
|
||||
if (isArrayed && dim0 == 3) // there are no 3D arrayed textures.
|
||||
// there are no 3D arrayed textures, or 3D SampleCmp
|
||||
if (dim0 == 3 && (isArrayed || name == "SampleCmp"))
|
||||
return true;
|
||||
|
||||
const int numArgs = int(std::count(argOrder, argOrder + strlen(argOrder), ',')) + 1;
|
||||
|
||||
// Reject invalid offset arrayed forms.
|
||||
// Reject invalid offset arrayed forms with cubemaps
|
||||
if (isArrayed && dim0 == 4) {
|
||||
if (name == "Sample" && numArgs == 4)
|
||||
if ((name == "Sample" && numArgs >= 4) ||
|
||||
(name == "SampleBias" && numArgs >= 5) ||
|
||||
(name == "SampleCmp" && numArgs >= 5) ||
|
||||
(name == "SampleCmpLevelZero" && numArgs >= 4) ||
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -103,6 +118,7 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
|
||||
const bool isMatMul = (argOrder[0] == '#');
|
||||
const bool isTexture = IsTextureType(argOrder[0]);
|
||||
const bool isArrayed = IsTextureArrayed(argOrder[0]);
|
||||
const bool isMS = IsTextureMS(argOrder[0]);
|
||||
|
||||
char order = *argOrder;
|
||||
char type = *argType;
|
||||
@@ -187,14 +203,14 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
|
||||
switch (order) {
|
||||
case '-': break; // no dimensions for voids
|
||||
case 'S': break; // no dimensions on scalars
|
||||
case 'V': s += ('0' + (char)dim0); break;
|
||||
case 'V': s += ('0' + char(dim0)); break;
|
||||
case 'M':
|
||||
{
|
||||
if (!UseHlslTypes) // GLSL has column first for mat types
|
||||
std::swap(dim0, dim1);
|
||||
s += ('0' + (char)dim0);
|
||||
s += ('0' + char(dim0));
|
||||
s += 'x';
|
||||
s += ('0' + (char)dim1);
|
||||
s += ('0' + char(dim1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -517,10 +533,43 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
|
||||
// Texture object methods. Return type can be overridden by shader declaration.
|
||||
// !O = no offset, O = offset, !A = no array, A = array
|
||||
{ "Sample", /*!O !A*/ "V4", nullptr, "%V,S,V", "FIU,S,F", EShLangFragmentMask },
|
||||
{ "Sample", /* O !A*/ "V4", nullptr, "%V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
|
||||
{ "Sample", /*!O A*/ "V4", nullptr, "@V,S,V", "FIU,S,F", EShLangFragmentMask },
|
||||
{ "Sample", /* O A*/ "V4", nullptr, "@V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
|
||||
{ "Sample", /*!O !A*/ "V4", nullptr, "%V,S,V", "FIU,S,F", EShLangFragmentMask },
|
||||
{ "Sample", /* O !A*/ "V4", nullptr, "%V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
|
||||
{ "Sample", /*!O A*/ "V4", nullptr, "@V,S,V", "FIU,S,F", EShLangFragmentMask },
|
||||
{ "Sample", /* O A*/ "V4", nullptr, "@V,S,V,V", "FIU,S,F,I", EShLangFragmentMask },
|
||||
|
||||
{ "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 },
|
||||
{ "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 },
|
||||
|
||||
// { "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 },
|
||||
|
||||
{ "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 },
|
||||
|
||||
// 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 },
|
||||
|
||||
// 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 },
|
||||
@@ -565,7 +614,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
continue;
|
||||
|
||||
// Reject some forms of sample methods that don't exist.
|
||||
if (isTexture && IsIllegalSample(s, argOrder, dim0))
|
||||
if (isTexture && IsIllegalSample(intrinsic.name, argOrder, dim0))
|
||||
continue;
|
||||
|
||||
AppendTypeName(s, retOrder, retType, dim0, dim1); // add return type
|
||||
@@ -796,6 +845,12 @@ 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("SampleGrad", EOpMethodSampleGrad);
|
||||
// symbolTable.relateToOperator("SampleLevel", EOpMethodSampleLevel);
|
||||
// symbolTable.relateToOperator("Load", EOpMethodLoad);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user