Merge pull request #551 from steve-lunarg/rwbuffers-fmt

HLSL: phase 3 of rwtexture support: add sub-vec4 capabilities
This commit is contained in:
John Kessenich
2016-10-15 23:03:38 -06:00
committed by GitHub
48 changed files with 6671 additions and 569 deletions

View File

@@ -907,12 +907,6 @@ bool HlslGrammar::acceptTextureType(TType& type)
return false;
}
if (txType.getVectorSize() != 1 && txType.getVectorSize() != 4) {
// TODO: handle vec2/3 types
expected("vector size not yet supported in texture type");
return false;
}
if (ms && acceptTokenClass(EHTokComma)) {
// read sample count for multisample types, if given
if (! peekTokenClass(EHTokIntConstant)) {
@@ -937,24 +931,14 @@ bool HlslGrammar::acceptTextureType(TType& type)
}
TArraySizes* arraySizes = nullptr;
const bool shadow = !image && (txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1));
const bool shadow = false; // declared on the sampler
TSampler sampler;
TLayoutFormat format = ElfNone;
// RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
if (image) {
if (txType.getVectorSize() != 4)
expected("4 component image");
switch (txType.getBasicType()) {
case EbtFloat: format = ElfRgba32f; break;
case EbtInt: format = ElfRgba32i; break;
case EbtUint: format = ElfRgba32ui; break;
default:
expected("unknown basic type in image format");
}
}
// Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
if (image || dim == EsdBuffer)
format = parseContext.getLayoutFromTxType(token.loc, txType);
// Non-image Buffers are combined
if (dim == EsdBuffer && !image) {
@@ -967,6 +951,9 @@ bool HlslGrammar::acceptTextureType(TType& type)
sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
}
}
// Remember the declared vector size.
sampler.vectorSize = txType.getVectorSize();
type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
type.getQualifier().layoutFormat = format;

View File

@@ -147,6 +147,31 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const
return false;
}
//
// Return a TLayoutFormat corresponding to the given texture type.
//
TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType)
{
const int components = txType.getVectorSize();
const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) {
if (intermediate.getNoStorageFormat())
return ElfNone;
return components == 1 ? v1 :
components == 2 ? v2 : v4;
};
switch (txType.getBasicType()) {
case EbtFloat: return selectFormat(ElfR32f, ElfRg32f, ElfRgba32f);
case EbtInt: return selectFormat(ElfR32i, ElfRg32i, ElfRgba32i);
case EbtUint: return selectFormat(ElfR32ui, ElfRg32ui, ElfRgba32ui);
default:
error(loc, "unknown basic type in image format", "", "");
return ElfNone;
}
}
//
// Both test and if necessary, spit out an error, to see if the node is really
// an l-value that can be operated on this way.
@@ -264,11 +289,9 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char*
TIntermTyped* object = lhsAsAggregate->getSequence()[0]->getAsTyped();
TIntermTyped* coord = lhsAsAggregate->getSequence()[1]->getAsTyped();
const TLayoutFormat fmt = object->getType().getQualifier().layoutFormat;
// We only handle 4 component formats at the moment.
const TSampler& texSampler = object->getType().getSampler();
assert(fmt == ElfRgba32f || fmt == ElfRgba32i || fmt == ElfRgba32ui);
const TType objDerefType(object->getType().getSampler().type, EvqTemporary, 4);
const TType objDerefType(texSampler.type, EvqTemporary, texSampler.vectorSize);
if (nodeAsBinary) {
TIntermTyped* rhs = nodeAsBinary->getRight();
@@ -578,10 +601,9 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn
if (base->getType().getBasicType() == EbtSampler && !base->isArray()) {
const TSampler& sampler = base->getType().getSampler();
if (sampler.isImage() || sampler.isTexture()) {
const int vecSize = 4; // TODO: handle arbitrary sizes (get from qualifier)
TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
load->setType(TType(sampler.type, EvqTemporary, vecSize));
load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize));
load->setLoc(loc);
load->getSequence().push_back(base);
load->getSequence().push_back(index);
@@ -1418,6 +1440,23 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
if (!node || !node->getAsOperator())
return;
const auto clampReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) {
// Sampler return must always be a vec4, but we can construct a shorter vector
result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize()));
if (sampler.vectorSize < node->getVectorSize()) {
// Too many components. Construct shorter vector from it.
const TType clampedType(result->getType().getBasicType(), EvqTemporary, sampler.vectorSize);
const TOperator op = intermediate.mapTypeToConstructorOp(clampedType);
result = constructBuiltIn(clampedType, op, result, loc, false);
}
result->setLoc(loc);
return result;
};
const TOperator op = node->getAsOperator()->getOp();
const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
@@ -1426,10 +1465,8 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
case EOpTexture:
{
// Texture with ddx & ddy is really gradient form in HLSL
if (argAggregate->getSequence().size() == 4) {
if (argAggregate->getSequence().size() == 4)
node->getAsAggregate()->setOperator(EOpTextureGrad);
break;
}
break;
}
@@ -1445,14 +1482,16 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
TIntermTyped* bias = intermediate.addIndex(EOpIndexDirect, arg1, w, loc);
TOperator constructOp = EOpNull;
switch (arg0->getType().getSampler().dim) {
const TSampler& sampler = arg0->getType().getSampler();
switch (sampler.dim) {
case Esd1D: constructOp = EOpConstructFloat; break; // 1D
case Esd2D: constructOp = EOpConstructVec2; break; // 2D
case Esd3D: constructOp = EOpConstructVec3; break; // 3D
case EsdCube: constructOp = EOpConstructVec3; break; // also 3D
default: break;
}
TIntermAggregate* constructCoord = new TIntermAggregate(constructOp);
constructCoord->getSequence().push_back(arg1);
constructCoord->setLoc(loc);
@@ -1461,8 +1500,8 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
tex->getSequence().push_back(arg0); // sampler
tex->getSequence().push_back(constructCoord); // coordinate
tex->getSequence().push_back(bias); // bias
tex->setLoc(loc);
node = tex;
node = clampReturn(tex, sampler);
break;
}
@@ -1476,6 +1515,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
TIntermTyped* argBias = nullptr;
TIntermTyped* argOffset = nullptr;
const TSampler& sampler = argTex->getType().getSampler();
int nextArg = 3;
@@ -1501,9 +1541,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
if (argOffset != nullptr)
txsample->getSequence().push_back(argOffset);
txsample->setType(node->getType());
txsample->setLoc(loc);
node = txsample;
node = clampReturn(txsample, sampler);
break;
}
@@ -1516,6 +1554,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
TIntermTyped* argDDX = argAggregate->getSequence()[3]->getAsTyped();
TIntermTyped* argDDY = argAggregate->getSequence()[4]->getAsTyped();
TIntermTyped* argOffset = nullptr;
const TSampler& sampler = argTex->getType().getSampler();
TOperator textureOp = EOpTextureGrad;
@@ -1535,9 +1574,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
if (argOffset != nullptr)
txsample->getSequence().push_back(argOffset);
txsample->setType(node->getType());
txsample->setLoc(loc);
node = txsample;
node = clampReturn(txsample, sampler);
break;
}
@@ -1556,9 +1593,9 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
assert(texType.getBasicType() == EbtSampler);
const TSampler& texSampler = texType.getSampler();
const TSamplerDim dim = texSampler.dim;
const bool isImage = texSampler.isImage();
const TSampler& sampler = texType.getSampler();
const TSamplerDim dim = sampler.dim;
const bool isImage = sampler.isImage();
const int numArgs = (int)argAggregate->getSequence().size();
int numDims = 0;
@@ -1574,11 +1611,11 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
}
// Arrayed adds another dimension for the number of array elements
if (texSampler.isArrayed())
if (sampler.isArrayed())
++numDims;
// Establish whether we're querying mip levels
const bool mipQuery = (numArgs > (numDims + 1)) && (!texSampler.isMultiSample());
const bool mipQuery = (numArgs > (numDims + 1)) && (!sampler.isMultiSample());
// AST assumes integer return. Will be converted to float if required.
TIntermAggregate* sizeQuery = new TIntermAggregate(isImage ? EOpImageQuerySize : EOpTextureQuerySize);
@@ -1636,7 +1673,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
}
// 2DMS formats query # samples, which needs a different query op
if (texSampler.isMultiSample()) {
if (sampler.isMultiSample()) {
TIntermTyped* outParam = argAggregate->getSequence()[outParamBase + numDims]->getAsTyped();
TIntermAggregate* samplesQuery = new TIntermAggregate(EOpImageQuerySamples);
@@ -1725,9 +1762,10 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
TIntermTyped* lodComponent = nullptr;
TIntermTyped* coordSwizzle = nullptr;
const bool isMS = argTex->getType().getSampler().isMultiSample();
const bool isBuffer = argTex->getType().getSampler().dim == EsdBuffer;
const bool isImage = argTex->getType().getSampler().isImage();
const TSampler& sampler = argTex->getType().getSampler();
const bool isMS = sampler.isMultiSample();
const bool isBuffer = sampler.dim == EsdBuffer;
const bool isImage = sampler.isImage();
const TBasicType coordBaseType = argCoord->getType().getBasicType();
// Last component of coordinate is the mip level, for non-MS. we separate them here:
@@ -1781,9 +1819,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
txfetch->getSequence().push_back(argOffset);
}
txfetch->setType(node->getType());
txfetch->setLoc(loc);
node = txfetch;
node = clampReturn(txfetch, sampler);
break;
}
@@ -1795,7 +1831,8 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
TIntermTyped* argLod = argAggregate->getSequence()[3]->getAsTyped();
TIntermTyped* argOffset = nullptr;
const TSampler& sampler = argTex->getType().getSampler();
const int numArgs = (int)argAggregate->getSequence().size();
if (numArgs == 5) // offset, if present
@@ -1813,9 +1850,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
if (argOffset != nullptr)
txsample->getSequence().push_back(argOffset);
txsample->setType(node->getType());
txsample->setLoc(loc);
node = txsample;
node = clampReturn(txsample, sampler);
break;
}

View File

@@ -156,6 +156,8 @@ public:
TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped* node);
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
protected:
void inheritGlobalDefaults(TQualifier& dst) const;
TVariable* makeInternalVariable(const char* name, const TType&) const;

View File

@@ -708,15 +708,15 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
{ "SampleLevel", /*!O*/ "V4", nullptr, "%@,S,V,S", "FIU,S,F,", EShLangAll },
{ "SampleLevel", /* O*/ "V4", nullptr, "%@,S,V,S,V", "FIU,S,F,,I", EShLangAll },
{ "Load", /*!O*/ "V4", nullptr, "%@*,V", "FIU,I", EShLangAll },
{ "Load", /*!O*/ "V4", nullptr, "%@,V", "FIU,I", EShLangAll },
{ "Load", /* O*/ "V4", nullptr, "%@,V,V", "FIU,I,I", EShLangAll },
{ "Load", /* +sampleidex*/ "V4", nullptr, "$&,V,S", "FIU,I,I", EShLangAll },
{ "Load", /* +samplindex, offset*/ "V4", nullptr, "$&,V,S,V", "FIU,I,I,I", EShLangAll },
// RWTexture loads
{ "Load", "V4", nullptr, "!#,V", "FIU,I", EShLangAll },
// RWBuffer loads
{ "Load", "V4", nullptr, "~1,V", "FIU,I", EShLangAll },
// (RW)Buffer loads
{ "Load", "V4", nullptr, "~*1,V", "FIU,I", EShLangAll },
{ "Gather", /*!O*/ "V4", nullptr, "%@,S,V", "FIU,S,F", EShLangAll },
{ "Gather", /* O*/ "V4", nullptr, "%@,S,V,V", "FIU,S,F,I", EShLangAll },