WIP: HLSL: Support InputPatch variables in patch constant functions

Previously, patch constant functions only accepted OutputPatch.  This
adds InputPatch support, via a pseudo-builtin variable type, so that
the patch can be tracked clear through from the qualifier.
This commit is contained in:
steve-lunarg
2017-04-01 15:34:48 -06:00
parent b68b9a8b23
commit 067eb9b48a
8 changed files with 739 additions and 34 deletions

View File

@@ -67,7 +67,8 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
sourceEntryPointName(sourceEntryPointName),
entryPointFunction(nullptr),
entryPointFunctionBody(nullptr),
gsStreamOutput(nullptr)
gsStreamOutput(nullptr),
inputPatch(nullptr)
{
globalUniformDefaults.clear();
globalUniformDefaults.layoutMatrix = ElmRowMajor;
@@ -1377,6 +1378,7 @@ TIntermTyped* HlslParseContext::splitAccessStruct(const TSourceLoc& loc, TInterm
void HlslParseContext::trackLinkage(TSymbol& symbol)
{
TBuiltInVariable biType = symbol.getType().getQualifier().builtIn;
if (biType != EbvNone)
builtInLinkageSymbols[biType] = symbol.clone();
@@ -1811,6 +1813,7 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
else if (variable.getType().containsBuiltInInterstageIO(language))
split(variable);
}
assignLocations(variable);
};
if (entryPointOutput)
@@ -1988,6 +1991,7 @@ void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& return
correctOutput(ioVariable->getWritableType().getQualifier());
}
ioVariable->getWritableType().getQualifier().storage = storage;
return ioVariable;
};
@@ -2022,6 +2026,9 @@ void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& return
if (paramType.getQualifier().isParamInput()) {
TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingIn);
inputs.push_back(argAsGlobal);
if (function[i].declaredBuiltIn == EbvInputPatch)
inputPatch = argAsGlobal;
}
if (paramType.getQualifier().isParamOutput()) {
TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType, EvqVaryingOut);
@@ -7574,7 +7581,10 @@ void HlslParseContext::addPatchConstantInvocation()
// Look for builtin variables in a function's parameter list.
const auto findBuiltIns = [&](const TFunction& function, std::set<tInterstageIoData>& builtIns) {
for (int p=0; p<function.getParamCount(); ++p) {
const TStorageQualifier storage = function[p].type->getQualifier().storage;
TStorageQualifier storage = function[p].type->getQualifier().storage;
if (storage == EvqConstReadOnly) // treated identically to input
storage = EvqIn;
if (function[p].declaredBuiltIn != EbvNone)
builtIns.insert(HlslParseContext::tInterstageIoData(function[p].declaredBuiltIn, storage));
@@ -7605,9 +7615,11 @@ void HlslParseContext::addPatchConstantInvocation()
}
};
const auto isPerCtrlPt = [this](const TType& type) {
// TODO: this is not sufficient to reject all such cases in malformed shaders.
return type.isArray() && !type.isRuntimeSizedArray();
const auto isOutputPatch = [this](TFunction& patchConstantFunction, int param) {
const TType& type = *patchConstantFunction[param].type;
const TBuiltInVariable biType = patchConstantFunction[param].declaredBuiltIn;
return type.isArray() && !type.isRuntimeSizedArray() && biType == EbvOutputPatch;
};
// We will perform these steps. Each is in a scoped block for separation: they could
@@ -7636,7 +7648,7 @@ void HlslParseContext::addPatchConstantInvocation()
TIntermSymbol* invocationIdSym = findLinkageSymbol(EbvInvocationId);
TIntermSequence& epBodySeq = entryPointFunctionBody->getAsAggregate()->getSequence();
int perCtrlPtParam = -1; // -1 means there isn't one.
int outPatchParam = -1; // -1 means there isn't one.
// ================ Step 1A: Union Interfaces ================
// Our patch constant function.
@@ -7662,25 +7674,37 @@ void HlslParseContext::addPatchConstantInvocation()
// Now we'll add those to the entry and to the linkage.
for (int p=0; p<pcfParamCount; ++p) {
const TBuiltInVariable biType = patchConstantFunction[p].declaredBuiltIn;
const TStorageQualifier storage = patchConstantFunction[p].type->getQualifier().storage;
TStorageQualifier storage = patchConstantFunction[p].type->getQualifier().storage;
// Track whether there is any per control point input
if (isPerCtrlPt(*patchConstantFunction[p].type)) {
if (perCtrlPtParam >= 0) {
// Presently we only support one per ctrl pt input. TODO: does HLSL even allow multiple?
error(loc, "unimplemented: multiple per control point inputs to patch constant function", "", "");
// Track whether there is an output patch param
if (isOutputPatch(patchConstantFunction, p)) {
if (outPatchParam >= 0) {
// Presently we only support one per ctrl pt input.
error(loc, "unimplemented: multiple output patches in patch constant function", "", "");
return;
}
perCtrlPtParam = p;
outPatchParam = p;
}
if (biType != EbvNone) {
TType* paramType = patchConstantFunction[p].type->clone();
// Use the original declaration type for the linkage
paramType->getQualifier().builtIn = biType;
if (notInEntryPoint.count(tInterstageIoData(biType, storage)) == 1)
addToLinkage(*paramType, patchConstantFunction[p].name, nullptr);
if (storage == EvqConstReadOnly) // treated identically to input
storage = EvqIn;
// Presently, the only non-builtin we support is InputPatch, which is treated as
// a pseudo-builtin.
if (biType == EbvInputPatch) {
builtInLinkageSymbols[biType] = inputPatch;
} else if (biType == EbvOutputPatch) {
// Nothing...
} else {
// Use the original declaration type for the linkage
paramType->getQualifier().builtIn = biType;
if (notInEntryPoint.count(tInterstageIoData(biType, storage)) == 1)
addToLinkage(*paramType, patchConstantFunction[p].name, nullptr);
}
}
}
@@ -7703,18 +7727,12 @@ void HlslParseContext::addPatchConstantInvocation()
// TODO: handle struct or array inputs
{
for (int p=0; p<pcfParamCount; ++p) {
if ((patchConstantFunction[p].type->isArray() && !isPerCtrlPt(*patchConstantFunction[p].type)) ||
(!patchConstantFunction[p].type->isArray() && patchConstantFunction[p].type->isStruct())) {
error(loc, "unimplemented array or variable in patch constant function signature", "", "");
return;
}
TIntermSymbol* inputArg = nullptr;
if (p == perCtrlPtParam) {
if (p == outPatchParam) {
if (perCtrlPtVar == nullptr) {
perCtrlPtVar = makeInternalVariable(*patchConstantFunction[perCtrlPtParam].name,
*patchConstantFunction[perCtrlPtParam].type);
perCtrlPtVar = makeInternalVariable(*patchConstantFunction[outPatchParam].name,
*patchConstantFunction[outPatchParam].type);
perCtrlPtVar->getWritableType().getQualifier().makeTemporary();
}
@@ -7724,7 +7742,7 @@ void HlslParseContext::addPatchConstantInvocation()
const TBuiltInVariable biType = patchConstantFunction[p].declaredBuiltIn;
inputArg = findLinkageSymbol(biType);
if (inputArg == nullptr) {
error(loc, "unable to find patch constant function builtin variable", "", "");
return;
@@ -7769,9 +7787,9 @@ void HlslParseContext::addPatchConstantInvocation()
// invocations of the entry point to build up an array, or (TODO:) use a yet
// unavailable extension to look across the SIMD lanes. This is the former
// as a placeholder for the latter.
if (perCtrlPtParam >= 0) {
if (outPatchParam >= 0) {
// We must introduce a local temp variable of the type wanted by the PCF input.
const int arraySize = patchConstantFunction[perCtrlPtParam].type->getOuterArraySize();
const int arraySize = patchConstantFunction[outPatchParam].type->getOuterArraySize();
if (entryPointFunction->getType().getBasicType() == EbtVoid) {
error(loc, "entry point must return a value for use with patch constant function", "", "");