Merge pull request #1017 from LoopDawg/texture-struct-return.1
HLSL: add methods to handle user structures in texture template type.
This commit is contained in:
commit
b207daa5d3
1184
Test/baseResults/hlsl.texture.struct.frag.out
Normal file
1184
Test/baseResults/hlsl.texture.struct.frag.out
Normal file
File diff suppressed because it is too large
Load Diff
55
Test/hlsl.texture.struct.frag
Normal file
55
Test/hlsl.texture.struct.frag
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
struct s1_t {
|
||||||
|
float c0;
|
||||||
|
float2 c1;
|
||||||
|
float c2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct s2_t {
|
||||||
|
float c0;
|
||||||
|
float3 c1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct s3_t {
|
||||||
|
float2 c0;
|
||||||
|
float1 c1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct s4_t {
|
||||||
|
int c0;
|
||||||
|
int2 c1;
|
||||||
|
int c2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct s5_t {
|
||||||
|
uint c0;
|
||||||
|
uint c1;
|
||||||
|
};
|
||||||
|
|
||||||
|
SamplerState g_sSamp;
|
||||||
|
Texture2D <s1_t> g_tTex2s1;
|
||||||
|
Texture2D <s2_t> g_tTex2s2;
|
||||||
|
Texture2D <s3_t> g_tTex2s3;
|
||||||
|
Texture2D <s4_t> g_tTex2s4;
|
||||||
|
Texture2D <s5_t> g_tTex2s5;
|
||||||
|
|
||||||
|
Texture2D <s1_t> g_tTex2s1a; // same type as g_tTex2s1, to test fn signature matching.
|
||||||
|
|
||||||
|
// function overloading to test name mangling with textures templatized on structs
|
||||||
|
s1_t fn1(Texture2D <s1_t> t1) { return t1 . Sample(g_sSamp, float2(0.6, 0.61)); }
|
||||||
|
s2_t fn1(Texture2D <s2_t> t2) { return t2 . Sample(g_sSamp, float2(0.6, 0.61)); }
|
||||||
|
|
||||||
|
float4 main() : SV_Target0
|
||||||
|
{
|
||||||
|
s1_t s1 = g_tTex2s1 . Sample(g_sSamp, float2(0.1, 0.11));
|
||||||
|
s2_t s2 = g_tTex2s2 . Sample(g_sSamp, float2(0.2, 0.21));
|
||||||
|
s3_t s3 = g_tTex2s3 . Sample(g_sSamp, float2(0.3, 0.31));
|
||||||
|
s4_t s4 = g_tTex2s4 . Sample(g_sSamp, float2(0.4, 0.41));
|
||||||
|
s5_t s5 = g_tTex2s5 . Sample(g_sSamp, float2(0.5, 0.51));
|
||||||
|
|
||||||
|
s1_t r0 = fn1(g_tTex2s1);
|
||||||
|
s2_t r1 = fn1(g_tTex2s2);
|
||||||
|
s1_t r2 = fn1(g_tTex2s1a);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ Texture2D <float4> g_tTex2df4;
|
|||||||
|
|
||||||
SamplerState g_sSamp;
|
SamplerState g_sSamp;
|
||||||
|
|
||||||
float4 main()
|
float4 main() : SV_Target0
|
||||||
{
|
{
|
||||||
uint MipLevel;
|
uint MipLevel;
|
||||||
uint WidthU;
|
uint WidthU;
|
||||||
|
@ -80,7 +80,19 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||||||
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
|
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
|
||||||
bool sampler : 1; // true means a pure sampler, other fields should be clear()
|
bool sampler : 1; // true means a pure sampler, other fields should be clear()
|
||||||
bool external : 1; // GL_OES_EGL_image_external
|
bool external : 1; // GL_OES_EGL_image_external
|
||||||
unsigned int vectorSize : 3; // return vector size. TODO: support arbitrary types.
|
unsigned int vectorSize : 3; // vector return type size.
|
||||||
|
|
||||||
|
// Some languages support structures as sample results. Storing the whole structure in the
|
||||||
|
// TSampler is too large, so there is an index to a separate table.
|
||||||
|
static const unsigned structReturnIndexBits = 4; // number of index bits to use.
|
||||||
|
static const unsigned structReturnSlots = (1<<structReturnIndexBits)-1; // number of valid values
|
||||||
|
static const unsigned noReturnStruct = structReturnSlots; // value if no return struct type.
|
||||||
|
|
||||||
|
// Index into a language specific table of texture return structures.
|
||||||
|
unsigned int structReturnIndex : structReturnIndexBits;
|
||||||
|
|
||||||
|
// Encapsulate getting members' vector sizes packed into the vectorSize bitfield.
|
||||||
|
unsigned int getVectorSize() const { return vectorSize; }
|
||||||
|
|
||||||
bool isImage() const { return image && dim != EsdSubpass; }
|
bool isImage() const { return image && dim != EsdSubpass; }
|
||||||
bool isSubpass() const { return dim == EsdSubpass; }
|
bool isSubpass() const { return dim == EsdSubpass; }
|
||||||
@ -90,6 +102,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||||||
bool isShadow() const { return shadow; }
|
bool isShadow() const { return shadow; }
|
||||||
bool isArrayed() const { return arrayed; }
|
bool isArrayed() const { return arrayed; }
|
||||||
bool isMultiSample() const { return ms; }
|
bool isMultiSample() const { return ms; }
|
||||||
|
bool hasReturnStruct() const { return structReturnIndex != noReturnStruct; }
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
@ -102,6 +115,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||||||
combined = false;
|
combined = false;
|
||||||
sampler = false;
|
sampler = false;
|
||||||
external = false;
|
external = false;
|
||||||
|
structReturnIndex = noReturnStruct;
|
||||||
|
|
||||||
|
// by default, returns a single vec4;
|
||||||
vectorSize = 4;
|
vectorSize = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +185,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||||||
combined == right.combined &&
|
combined == right.combined &&
|
||||||
sampler == right.sampler &&
|
sampler == right.sampler &&
|
||||||
external == right.external &&
|
external == right.external &&
|
||||||
vectorSize == right.vectorSize;
|
vectorSize == right.vectorSize &&
|
||||||
|
structReturnIndex == right.structReturnIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const TSampler& right) const
|
bool operator!=(const TSampler& right) const
|
||||||
|
@ -104,12 +104,21 @@ void TType::buildMangledName(TString& mangledName) const
|
|||||||
default: break; // some compilers want this
|
default: break; // some compilers want this
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sampler.vectorSize) {
|
if (sampler.hasReturnStruct()) {
|
||||||
|
// Name mangle for sampler return struct uses struct table index.
|
||||||
|
mangledName += "-tx-struct";
|
||||||
|
|
||||||
|
char text[16]; // plenty enough space for the small integers.
|
||||||
|
snprintf(text, sizeof(text), "%d-", sampler.structReturnIndex);
|
||||||
|
mangledName += text;
|
||||||
|
} else {
|
||||||
|
switch (sampler.getVectorSize()) {
|
||||||
case 1: mangledName += "1"; break;
|
case 1: mangledName += "1"; break;
|
||||||
case 2: mangledName += "2"; break;
|
case 2: mangledName += "2"; break;
|
||||||
case 3: mangledName += "3"; break;
|
case 3: mangledName += "3"; break;
|
||||||
case 4: break; // default to prior name mangle behavior
|
case 4: break; // default to prior name mangle behavior
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sampler.ms)
|
if (sampler.ms)
|
||||||
mangledName += "M";
|
mangledName += "M";
|
||||||
|
@ -291,6 +291,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
{"hlsl.structIoFourWay.frag", "main"},
|
{"hlsl.structIoFourWay.frag", "main"},
|
||||||
{"hlsl.structStructName.frag", "main"},
|
{"hlsl.structStructName.frag", "main"},
|
||||||
{"hlsl.synthesizeInput.frag", "main"},
|
{"hlsl.synthesizeInput.frag", "main"},
|
||||||
|
{"hlsl.texture.struct.frag", "main"},
|
||||||
{"hlsl.texture.subvec4.frag", "main"},
|
{"hlsl.texture.subvec4.frag", "main"},
|
||||||
{"hlsl.this.frag", "main"},
|
{"hlsl.this.frag", "main"},
|
||||||
{"hlsl.intrinsics.vert", "VertexShaderFunction"},
|
{"hlsl.intrinsics.vert", "VertexShaderFunction"},
|
||||||
|
@ -1189,7 +1189,13 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
|||||||
|
|
||||||
const TBasicType basicRetType = txType.getBasicType() ;
|
const TBasicType basicRetType = txType.getBasicType() ;
|
||||||
|
|
||||||
if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
|
switch (basicRetType) {
|
||||||
|
case EbtFloat:
|
||||||
|
case EbtUint:
|
||||||
|
case EbtInt:
|
||||||
|
case EbtStruct:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
unimplemented("basic type in texture");
|
unimplemented("basic type in texture");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1206,8 +1212,8 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!txType.isScalar() && !txType.isVector()) {
|
if (!txType.isScalar() && !txType.isVector() && !txType.isStruct()) {
|
||||||
expected("scalar or vector type");
|
expected("scalar, vector, or struct type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1244,20 +1250,24 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
|||||||
if (image || dim == EsdBuffer)
|
if (image || dim == EsdBuffer)
|
||||||
format = parseContext.getLayoutFromTxType(token.loc, txType);
|
format = parseContext.getLayoutFromTxType(token.loc, txType);
|
||||||
|
|
||||||
|
const TBasicType txBasicType = txType.isStruct() ? (*txType.getStruct())[0].type->getBasicType()
|
||||||
|
: txType.getBasicType();
|
||||||
|
|
||||||
// Non-image Buffers are combined
|
// Non-image Buffers are combined
|
||||||
if (dim == EsdBuffer && !image) {
|
if (dim == EsdBuffer && !image) {
|
||||||
sampler.set(txType.getBasicType(), dim, array);
|
sampler.set(txType.getBasicType(), dim, array);
|
||||||
} else {
|
} else {
|
||||||
// DX10 textures are separated. TODO: DX9.
|
// DX10 textures are separated. TODO: DX9.
|
||||||
if (image) {
|
if (image) {
|
||||||
sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
|
sampler.setImage(txBasicType, dim, array, shadow, ms);
|
||||||
} else {
|
} else {
|
||||||
sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
|
sampler.setTexture(txBasicType, dim, array, shadow, ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember the declared vector size.
|
// Remember the declared return type. Function returns false on error.
|
||||||
sampler.vectorSize = txType.getVectorSize();
|
if (!parseContext.setTextureReturnType(sampler, txType, token.loc))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Force uncombined, if necessary
|
// Force uncombined, if necessary
|
||||||
if (!combined)
|
if (!combined)
|
||||||
|
@ -189,7 +189,14 @@ void HlslParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memb
|
|||||||
//
|
//
|
||||||
TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType)
|
TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const TType& txType)
|
||||||
{
|
{
|
||||||
|
if (txType.isStruct()) {
|
||||||
|
// TODO: implement.
|
||||||
|
error(loc, "unimplemented: structure type in image or buffer", "", "");
|
||||||
|
return ElfNone;
|
||||||
|
}
|
||||||
|
|
||||||
const int components = txType.getVectorSize();
|
const int components = txType.getVectorSize();
|
||||||
|
const TBasicType txBasicType = txType.getBasicType();
|
||||||
|
|
||||||
const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) -> TLayoutFormat {
|
const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) -> TLayoutFormat {
|
||||||
if (intermediate.getNoStorageFormat())
|
if (intermediate.getNoStorageFormat())
|
||||||
@ -199,7 +206,7 @@ TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const
|
|||||||
components == 2 ? v2 : v4;
|
components == 2 ? v2 : v4;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (txType.getBasicType()) {
|
switch (txBasicType) {
|
||||||
case EbtFloat: return selectFormat(ElfR32f, ElfRg32f, ElfRgba32f);
|
case EbtFloat: return selectFormat(ElfR32f, ElfRg32f, ElfRgba32f);
|
||||||
case EbtInt: return selectFormat(ElfR32i, ElfRg32i, ElfRgba32i);
|
case EbtInt: return selectFormat(ElfR32i, ElfRg32i, ElfRgba32i);
|
||||||
case EbtUint: return selectFormat(ElfR32ui, ElfRg32ui, ElfRgba32ui);
|
case EbtUint: return selectFormat(ElfR32ui, ElfRg32ui, ElfRgba32ui);
|
||||||
@ -370,7 +377,8 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char*
|
|||||||
|
|
||||||
const TSampler& texSampler = object->getType().getSampler();
|
const TSampler& texSampler = object->getType().getSampler();
|
||||||
|
|
||||||
const TType objDerefType(texSampler.type, EvqTemporary, texSampler.vectorSize);
|
TType objDerefType;
|
||||||
|
getTextureReturnType(texSampler, objDerefType);
|
||||||
|
|
||||||
if (nodeAsBinary) {
|
if (nodeAsBinary) {
|
||||||
TIntermTyped* rhs = nodeAsBinary->getRight();
|
TIntermTyped* rhs = nodeAsBinary->getRight();
|
||||||
@ -771,7 +779,10 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn
|
|||||||
} else {
|
} else {
|
||||||
TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
|
TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
|
||||||
|
|
||||||
load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize));
|
TType sampReturnType;
|
||||||
|
getTextureReturnType(sampler, sampReturnType);
|
||||||
|
|
||||||
|
load->setType(sampReturnType);
|
||||||
load->setLoc(loc);
|
load->setLoc(loc);
|
||||||
load->getSequence().push_back(base);
|
load->getSequence().push_back(base);
|
||||||
load->getSequence().push_back(index);
|
load->getSequence().push_back(index);
|
||||||
@ -3292,21 +3303,99 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
if (node == nullptr || !node->getAsOperator())
|
if (node == nullptr || !node->getAsOperator())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto clampReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* {
|
// Sampler return must always be a vec4, but we can construct a shorter vector or a structure from it.
|
||||||
// Sampler return must always be a vec4, but we can construct a shorter vector
|
const auto convertReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* {
|
||||||
result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize()));
|
result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize()));
|
||||||
|
|
||||||
if (sampler.vectorSize < (unsigned)node->getVectorSize()) {
|
TIntermTyped* convertedResult = nullptr;
|
||||||
// Too many components. Construct shorter vector from it.
|
|
||||||
const TType clampedType(result->getType().getBasicType(), EvqTemporary, sampler.vectorSize);
|
|
||||||
|
|
||||||
const TOperator op = intermediate.mapTypeToConstructorOp(clampedType);
|
TType retType;
|
||||||
|
getTextureReturnType(sampler, retType);
|
||||||
|
|
||||||
result = constructBuiltIn(clampedType, op, result, loc, false);
|
if (retType.isStruct()) {
|
||||||
|
// For type convenience, conversionAggregate points to the convertedResult (we know it's an aggregate here)
|
||||||
|
TIntermAggregate* conversionAggregate = new TIntermAggregate;
|
||||||
|
convertedResult = conversionAggregate;
|
||||||
|
|
||||||
|
// Convert vector output to return structure. We will need a temp symbol to copy the results to.
|
||||||
|
TVariable* structVar = makeInternalVariable("@sampleStructTemp", retType);
|
||||||
|
|
||||||
|
// We also need a temp symbol to hold the result of the texture. We don't want to re-fetch the
|
||||||
|
// sample each time we'll index into the result, so we'll copy to this, and index into the copy.
|
||||||
|
TVariable* sampleShadow = makeInternalVariable("@sampleResultShadow", result->getType());
|
||||||
|
|
||||||
|
// Initial copy from texture to our sample result shadow.
|
||||||
|
TIntermTyped* shadowCopy = intermediate.addAssign(EOpAssign, intermediate.addSymbol(*sampleShadow, loc),
|
||||||
|
result, loc);
|
||||||
|
|
||||||
|
conversionAggregate->getSequence().push_back(shadowCopy);
|
||||||
|
|
||||||
|
unsigned vec4Pos = 0;
|
||||||
|
|
||||||
|
for (unsigned m = 0; m < unsigned(retType.getStruct()->size()); ++m) {
|
||||||
|
const TType memberType(retType, m); // dereferenced type of the member we're about to assign.
|
||||||
|
|
||||||
|
// Check for bad struct members. This should have been caught upstream. Complain, because
|
||||||
|
// wwe don't know what to do with it. This algorithm could be generalized to handle
|
||||||
|
// other things, e.g, sub-structures, but HLSL doesn't allow them.
|
||||||
|
if (!memberType.isVector() && !memberType.isScalar()) {
|
||||||
|
error(loc, "expected: scalar or vector type in texture structure", "", "");
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->setLoc(loc);
|
// Index into the struct variable to find the member to assign.
|
||||||
return result;
|
TIntermTyped* structMember = intermediate.addIndex(EOpIndexDirectStruct,
|
||||||
|
intermediate.addSymbol(*structVar, loc),
|
||||||
|
intermediate.addConstantUnion(m, loc), loc);
|
||||||
|
|
||||||
|
structMember->setType(memberType);
|
||||||
|
|
||||||
|
// Assign each component of (possible) vector in struct member.
|
||||||
|
for (int component = 0; component < memberType.getVectorSize(); ++component) {
|
||||||
|
TIntermTyped* vec4Member = intermediate.addIndex(EOpIndexDirect,
|
||||||
|
intermediate.addSymbol(*sampleShadow, loc),
|
||||||
|
intermediate.addConstantUnion(vec4Pos++, loc), loc);
|
||||||
|
vec4Member->setType(TType(memberType.getBasicType(), EvqTemporary, 1));
|
||||||
|
|
||||||
|
TIntermTyped* memberAssign = nullptr;
|
||||||
|
|
||||||
|
if (memberType.isVector()) {
|
||||||
|
// Vector member: we need to create an access chain to the vector component.
|
||||||
|
|
||||||
|
TIntermTyped* structVecComponent = intermediate.addIndex(EOpIndexDirect, structMember,
|
||||||
|
intermediate.addConstantUnion(component, loc), loc);
|
||||||
|
|
||||||
|
memberAssign = intermediate.addAssign(EOpAssign, structVecComponent, vec4Member, loc);
|
||||||
|
} else {
|
||||||
|
// Scalar member: we can assign to it directly.
|
||||||
|
memberAssign = intermediate.addAssign(EOpAssign, structMember, vec4Member, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
conversionAggregate->getSequence().push_back(memberAssign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add completed variable so the expression results in the whole struct value we just built.
|
||||||
|
conversionAggregate->getSequence().push_back(intermediate.addSymbol(*structVar, loc));
|
||||||
|
|
||||||
|
// Make it a sequence.
|
||||||
|
intermediate.setAggregateOperator(conversionAggregate, EOpSequence, retType, loc);
|
||||||
|
} else {
|
||||||
|
// vector clamp the output if template vector type is smaller than sample result.
|
||||||
|
if (retType.getVectorSize() < node->getVectorSize()) {
|
||||||
|
// Too many components. Construct shorter vector from it.
|
||||||
|
const TOperator op = intermediate.mapTypeToConstructorOp(retType);
|
||||||
|
|
||||||
|
convertedResult = constructBuiltIn(retType, op, result, loc, false);
|
||||||
|
} else {
|
||||||
|
// Enough components. Use directly.
|
||||||
|
convertedResult = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convertedResult->setLoc(loc);
|
||||||
|
return convertedResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TOperator op = node->getAsOperator()->getOp();
|
const TOperator op = node->getAsOperator()->getOp();
|
||||||
@ -3372,7 +3461,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
tex->getSequence().push_back(constructCoord); // coordinate
|
tex->getSequence().push_back(constructCoord); // coordinate
|
||||||
tex->getSequence().push_back(bias); // bias
|
tex->getSequence().push_back(bias); // bias
|
||||||
|
|
||||||
node = clampReturn(tex, sampler);
|
node = convertReturn(tex, sampler);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3412,7 +3501,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
if (argOffset != nullptr)
|
if (argOffset != nullptr)
|
||||||
txsample->getSequence().push_back(argOffset);
|
txsample->getSequence().push_back(argOffset);
|
||||||
|
|
||||||
node = clampReturn(txsample, sampler);
|
node = convertReturn(txsample, sampler);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3445,7 +3534,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
if (argOffset != nullptr)
|
if (argOffset != nullptr)
|
||||||
txsample->getSequence().push_back(argOffset);
|
txsample->getSequence().push_back(argOffset);
|
||||||
|
|
||||||
node = clampReturn(txsample, sampler);
|
node = convertReturn(txsample, sampler);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3721,7 +3810,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
txfetch->getSequence().push_back(argOffset);
|
txfetch->getSequence().push_back(argOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
node = clampReturn(txfetch, sampler);
|
node = convertReturn(txfetch, sampler);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3752,7 +3841,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
|||||||
if (argOffset != nullptr)
|
if (argOffset != nullptr)
|
||||||
txsample->getSequence().push_back(argOffset);
|
txsample->getSequence().push_back(argOffset);
|
||||||
|
|
||||||
node = clampReturn(txsample, sampler);
|
node = convertReturn(txsample, sampler);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -8756,6 +8845,106 @@ void HlslParseContext::clearUniformInputOutput(TQualifier& qualifier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set texture return type. Returns success (not all types are valid).
|
||||||
|
bool HlslParseContext::setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc)
|
||||||
|
{
|
||||||
|
// Seed the output with an invalid index. We will set it to a valid one if we can.
|
||||||
|
sampler.structReturnIndex = TSampler::noReturnStruct;
|
||||||
|
|
||||||
|
// Arrays aren't supported.
|
||||||
|
if (retType.isArray()) {
|
||||||
|
error(loc, "Arrays not supported in texture template types", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If return type is a vector, remember the vector size in the sampler, and return.
|
||||||
|
if (retType.isVector() || retType.isScalar()) {
|
||||||
|
sampler.vectorSize = retType.getVectorSize();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it wasn't a vector, it must be a struct meeting certain requirements. The requirements
|
||||||
|
// are checked below: just check for struct-ness here.
|
||||||
|
if (!retType.isStruct()) {
|
||||||
|
error(loc, "Invalid texture template type", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTypeList* members = retType.getWritableStruct();
|
||||||
|
|
||||||
|
// Check for too many or not enough structure members.
|
||||||
|
if (members->size() > 4 || members->size() == 0) {
|
||||||
|
error(loc, "Invalid member count in texture template structure", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error checking: We must have <= 4 total components, all of the same basic type.
|
||||||
|
unsigned totalComponents = 0;
|
||||||
|
for (unsigned m = 0; m < members->size(); ++m) {
|
||||||
|
// Check for bad member types
|
||||||
|
if (!(*members)[m].type->isScalar() && !(*members)[m].type->isVector()) {
|
||||||
|
error(loc, "Invalid texture template struct member type", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned memberVectorSize = (*members)[m].type->getVectorSize();
|
||||||
|
totalComponents += memberVectorSize;
|
||||||
|
|
||||||
|
// too many total member components
|
||||||
|
if (totalComponents > 4) {
|
||||||
|
error(loc, "Too many components in texture template structure type", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All members must be of a common basic type
|
||||||
|
if ((*members)[m].type->getBasicType() != (*members)[0].type->getBasicType()) {
|
||||||
|
error(loc, "Texture template structure members must same basic type", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the structure in the return type already exists in the table, we'll use it. Otherwise, we'll make
|
||||||
|
// a new entry. This is a linear search, but it hardly ever happens, and the list cannot be very large.
|
||||||
|
for (unsigned int idx = 0; idx < textureReturnStruct.size(); ++idx) {
|
||||||
|
if (textureReturnStruct[idx] == members) {
|
||||||
|
sampler.structReturnIndex = idx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It wasn't found as an existing entry. See if we have room for a new one.
|
||||||
|
if (textureReturnStruct.size() >= TSampler::structReturnSlots) {
|
||||||
|
error(loc, "Texture template struct return slots exceeded", "", "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert it in the vector that tracks struct return types.
|
||||||
|
sampler.structReturnIndex = unsigned(textureReturnStruct.size());
|
||||||
|
textureReturnStruct.push_back(members);
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the sampler return type in retType.
|
||||||
|
void HlslParseContext::getTextureReturnType(const TSampler& sampler, TType& retType) const
|
||||||
|
{
|
||||||
|
if (sampler.hasReturnStruct()) {
|
||||||
|
assert(textureReturnStruct.size() >= sampler.structReturnIndex);
|
||||||
|
|
||||||
|
// We land here if the texture return is a structure.
|
||||||
|
TTypeList* blockStruct = textureReturnStruct[sampler.structReturnIndex];
|
||||||
|
|
||||||
|
const TType resultType(blockStruct, "");
|
||||||
|
retType.shallowCopy(resultType);
|
||||||
|
} else {
|
||||||
|
// We land here if the texture return is a vector or scalar.
|
||||||
|
const TType resultType(sampler.type, EvqTemporary, sampler.getVectorSize());
|
||||||
|
retType.shallowCopy(resultType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return a symbol for the tessellation linkage variable of the given TBuiltInVariable type
|
// Return a symbol for the tessellation linkage variable of the given TBuiltInVariable type
|
||||||
TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const
|
TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const
|
||||||
{
|
{
|
||||||
|
@ -213,6 +213,12 @@ public:
|
|||||||
// Share struct buffer deep types
|
// Share struct buffer deep types
|
||||||
void shareStructBufferType(TType&);
|
void shareStructBufferType(TType&);
|
||||||
|
|
||||||
|
// Set texture return type of the given sampler. Returns success (not all types are valid).
|
||||||
|
bool setTextureReturnType(TSampler& sampler, const TType& retType, const TSourceLoc& loc);
|
||||||
|
|
||||||
|
// Obtain the sampler return type of the given sampler in retType.
|
||||||
|
void getTextureReturnType(const TSampler& sampler, TType& retType) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct TFlattenData {
|
struct TFlattenData {
|
||||||
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
|
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
|
||||||
@ -389,6 +395,10 @@ protected:
|
|||||||
// Structuredbuffer shared types. Typically there are only a few.
|
// Structuredbuffer shared types. Typically there are only a few.
|
||||||
TVector<TType*> structBufferTypes;
|
TVector<TType*> structBufferTypes;
|
||||||
|
|
||||||
|
// This tracks texture sample user structure return types. Only a limited number are supported, as
|
||||||
|
// may fit in TSampler::structReturnIndex.
|
||||||
|
TVector<TTypeList*> textureReturnStruct;
|
||||||
|
|
||||||
TMap<TString, bool> structBufferCounter;
|
TMap<TString, bool> structBufferCounter;
|
||||||
|
|
||||||
// The built-in interstage IO map considers e.g, EvqPosition on input and output separately, so that we
|
// The built-in interstage IO map considers e.g, EvqPosition on input and output separately, so that we
|
||||||
|
Loading…
x
Reference in New Issue
Block a user