HLSL: add standard sample position return form of GetSamplePosition method

Multisample textures support a GetSamplePosition() method intended to query
positions given a sample index.  This cannot be truly implemented in SPIR-V,
but #753 requested returning standard positions for the 1..16 cases, which
this PR adds.  Anything besides that returns (0,0).  If the standard positions
are not used, this will be wrong.

This should be revisited when there is a real query available.
This commit is contained in:
steve-lunarg
2017-04-26 08:31:56 -06:00
parent a1cdd13b1c
commit d4d0b29752
4 changed files with 935 additions and 36 deletions

View File

@@ -2843,7 +2843,73 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte
break; // most pass through unchanged
}
}
// Create array of standard sample positions for given sample count.
// TODO: remove when a real method to query sample pos exists in SPIR-V.
TIntermConstantUnion* HlslParseContext::getSamplePosArray(int count)
{
struct tSamplePos { float x, y; };
static const tSamplePos pos1[] = {
{ 0.0/16.0, 0.0/16.0 },
};
// standard sample positions for 2, 4, 8, and 16 samples.
static const tSamplePos pos2[] = {
{ 4.0/16.0, 4.0/16.0 }, {-4.0/16.0, -4.0/16.0 },
};
static const tSamplePos pos4[] = {
{-2.0/16.0, -6.0/16.0 }, { 6.0/16.0, -2.0/16.0 }, {-6.0/16.0, 2.0/16.0 }, { 2.0/16.0, 6.0/16.0 },
};
static const tSamplePos pos8[] = {
{ 1.0/16.0, -3.0/16.0 }, {-1.0/16.0, 3.0/16.0 }, { 5.0/16.0, 1.0/16.0 }, {-3.0/16.0, -5.0/16.0 },
{-5.0/16.0, 5.0/16.0 }, {-7.0/16.0, -1.0/16.0 }, { 3.0/16.0, 7.0/16.0 }, { 7.0/16.0, -7.0/16.0 },
};
static const tSamplePos pos16[] = {
{ 1.0/16.0, 1.0/16.0 }, {-1.0/16.0, -3.0/16.0 }, {-3.0/16.0, 2.0/16.0 }, { 4.0/16.0, -1.0/16.0 },
{-5.0/16.0, -2.0/16.0 }, { 2.0/16.0, 5.0/16.0 }, { 5.0/16.0, 3.0/16.0 }, { 3.0/16.0, -5.0/16.0 },
{-2.0/16.0, 6.0/16.0 }, { 0.0/16.0, -7.0/16.0 }, {-4.0/16.0, -6.0/16.0 }, {-6.0/16.0, 4.0/16.0 },
{-8.0/16.0, 0.0/16.0 }, { 7.0/16.0, -4.0/16.0 }, { 6.0/16.0, 7.0/16.0 }, {-7.0/16.0, -8.0/16.0 },
};
const tSamplePos* sampleLoc = nullptr;
int numSamples = count;
switch (count) {
case 2: sampleLoc = pos2; break;
case 4: sampleLoc = pos4; break;
case 8: sampleLoc = pos8; break;
case 16: sampleLoc = pos16; break;
default:
sampleLoc = pos1;
numSamples = 1;
}
TConstUnionArray* values = new TConstUnionArray(numSamples*2);
for (int pos=0; pos<count; ++pos) {
TConstUnion x, y;
x.setDConst(sampleLoc[pos].x);
y.setDConst(sampleLoc[pos].y);
(*values)[pos*2+0] = x;
(*values)[pos*2+1] = y;
}
TType retType(EbtFloat, EvqConst, 2);
if (numSamples != 1) {
TArraySizes arraySizes;
arraySizes.addInnerSize(numSamples);
retType.newArraySizes(arraySizes);
}
return new TIntermConstantUnion(*values, retType);
}
//
// Decompose DX9 and DX10 sample intrinsics & object methods into AST
//
@@ -3510,7 +3576,68 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
case EOpMethodGetSamplePosition:
{
error(loc, "unimplemented: GetSamplePosition", "", "");
// TODO: this entire decomposition exists because there is not yet a way to query
// the sample position directly through SPIR-V. Instead, we return fixed sample
// positions for common cases. *** If the sample positions are set differently,
// this will be wrong. ***
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
TIntermTyped* argSampIdx = argAggregate->getSequence()[1]->getAsTyped();
TIntermAggregate* samplesQuery = new TIntermAggregate(EOpImageQuerySamples);
samplesQuery->getSequence().push_back(argTex);
samplesQuery->setType(TType(EbtUint, EvqTemporary, 1));
samplesQuery->setLoc(loc);
TIntermAggregate* compoundStatement = nullptr;
TVariable* outSampleCount = makeInternalVariable("@sampleCount", TType(EbtUint));
outSampleCount->getWritableType().getQualifier().makeTemporary();
TIntermTyped* compAssign = intermediate.addAssign(EOpAssign, intermediate.addSymbol(*outSampleCount, loc),
samplesQuery, loc);
compoundStatement = intermediate.growAggregate(compoundStatement, compAssign);
TIntermTyped* idxtest[4];
// Create tests against 2, 4, 8, and 16 sample values
int count = 0;
for (int val = 2; val <= 16; val *= 2)
idxtest[count++] =
intermediate.addBinaryNode(EOpEqual,
intermediate.addSymbol(*outSampleCount, loc),
intermediate.addConstantUnion(val, loc),
loc, TType(EbtBool));
const TOperator idxOp = (argSampIdx->getQualifier().storage == EvqConst) ? EOpIndexDirect : EOpIndexIndirect;
// Create index ops into position arrays given sample index.
// TODO: should it be clamped?
TIntermTyped* index[4];
count = 0;
for (int val = 2; val <= 16; val *= 2) {
index[count] = intermediate.addIndex(idxOp, getSamplePosArray(val), argSampIdx, loc);
index[count++]->setType(TType(EbtFloat, EvqTemporary, 2));
}
// Create expression as:
// (sampleCount == 2) ? pos2[idx] :
// (sampleCount == 4) ? pos4[idx] :
// (sampleCount == 8) ? pos8[idx] :
// (sampleCount == 16) ? pos16[idx] : float2(0,0);
TIntermTyped* test =
intermediate.addSelection(idxtest[0], index[0],
intermediate.addSelection(idxtest[1], index[1],
intermediate.addSelection(idxtest[2], index[2],
intermediate.addSelection(idxtest[3], index[3],
getSamplePosArray(1), loc), loc), loc), loc);
compoundStatement = intermediate.growAggregate(compoundStatement, test);
compoundStatement->setOperator(EOpSequence);
compoundStatement->setLoc(loc);
compoundStatement->setType(TType(EbtFloat, EvqTemporary, 2));
node = compoundStatement;
break;
}

View File

@@ -273,6 +273,9 @@ protected:
// Test method names
bool isStructBufferMethod(const TString& name) const;
// Return standard sample position array
TIntermConstantUnion* getSamplePosArray(int count);
TType* getStructBufferContentType(const TType& type) const;
bool isStructBufferType(const TType& type) const { return getStructBufferContentType(type) != nullptr; }
TIntermTyped* indexStructBufferContent(const TSourceLoc& loc, TIntermTyped* buffer) const;