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;
|
||||
|
||||
float4 main()
|
||||
float4 main() : SV_Target0
|
||||
{
|
||||
uint MipLevel;
|
||||
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 sampler : 1; // true means a pure sampler, other fields should be clear()
|
||||
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 isSubpass() const { return dim == EsdSubpass; }
|
||||
@ -90,6 +102,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
||||
bool isShadow() const { return shadow; }
|
||||
bool isArrayed() const { return arrayed; }
|
||||
bool isMultiSample() const { return ms; }
|
||||
bool hasReturnStruct() const { return structReturnIndex != noReturnStruct; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
@ -102,6 +115,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
||||
combined = false;
|
||||
sampler = false;
|
||||
external = false;
|
||||
structReturnIndex = noReturnStruct;
|
||||
|
||||
// by default, returns a single vec4;
|
||||
vectorSize = 4;
|
||||
}
|
||||
|
||||
@ -160,16 +176,17 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
||||
|
||||
bool operator==(const TSampler& right) const
|
||||
{
|
||||
return type == right.type &&
|
||||
dim == right.dim &&
|
||||
arrayed == right.arrayed &&
|
||||
shadow == right.shadow &&
|
||||
ms == right.ms &&
|
||||
image == right.image &&
|
||||
combined == right.combined &&
|
||||
sampler == right.sampler &&
|
||||
external == right.external &&
|
||||
vectorSize == right.vectorSize;
|
||||
return type == right.type &&
|
||||
dim == right.dim &&
|
||||
arrayed == right.arrayed &&
|
||||
shadow == right.shadow &&
|
||||
ms == right.ms &&
|
||||
image == right.image &&
|
||||
combined == right.combined &&
|
||||
sampler == right.sampler &&
|
||||
external == right.external &&
|
||||
vectorSize == right.vectorSize &&
|
||||
structReturnIndex == right.structReturnIndex;
|
||||
}
|
||||
|
||||
bool operator!=(const TSampler& right) const
|
||||
|
@ -104,11 +104,20 @@ void TType::buildMangledName(TString& mangledName) const
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
|
||||
switch (sampler.vectorSize) {
|
||||
case 1: mangledName += "1"; break;
|
||||
case 2: mangledName += "2"; break;
|
||||
case 3: mangledName += "3"; break;
|
||||
case 4: break; // default to prior name mangle behavior
|
||||
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 2: mangledName += "2"; break;
|
||||
case 3: mangledName += "3"; break;
|
||||
case 4: break; // default to prior name mangle behavior
|
||||
}
|
||||
}
|
||||
|
||||
if (sampler.ms)
|
||||
|
@ -291,6 +291,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{"hlsl.structIoFourWay.frag", "main"},
|
||||
{"hlsl.structStructName.frag", "main"},
|
||||
{"hlsl.synthesizeInput.frag", "main"},
|
||||
{"hlsl.texture.struct.frag", "main"},
|
||||
{"hlsl.texture.subvec4.frag", "main"},
|
||||
{"hlsl.this.frag", "main"},
|
||||
{"hlsl.intrinsics.vert", "VertexShaderFunction"},
|
||||
|
@ -1189,7 +1189,13 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
||||
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
@ -1206,8 +1212,8 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!txType.isScalar() && !txType.isVector()) {
|
||||
expected("scalar or vector type");
|
||||
if (!txType.isScalar() && !txType.isVector() && !txType.isStruct()) {
|
||||
expected("scalar, vector, or struct type");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1244,20 +1250,24 @@ bool HlslGrammar::acceptTextureType(TType& type)
|
||||
if (image || dim == EsdBuffer)
|
||||
format = parseContext.getLayoutFromTxType(token.loc, txType);
|
||||
|
||||
const TBasicType txBasicType = txType.isStruct() ? (*txType.getStruct())[0].type->getBasicType()
|
||||
: txType.getBasicType();
|
||||
|
||||
// Non-image Buffers are combined
|
||||
if (dim == EsdBuffer && !image) {
|
||||
sampler.set(txType.getBasicType(), dim, array);
|
||||
} else {
|
||||
// DX10 textures are separated. TODO: DX9.
|
||||
if (image) {
|
||||
sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
|
||||
sampler.setImage(txBasicType, dim, array, shadow, ms);
|
||||
} else {
|
||||
sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
|
||||
sampler.setTexture(txBasicType, dim, array, shadow, ms);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember the declared vector size.
|
||||
sampler.vectorSize = txType.getVectorSize();
|
||||
// Remember the declared return type. Function returns false on error.
|
||||
if (!parseContext.setTextureReturnType(sampler, txType, token.loc))
|
||||
return false;
|
||||
|
||||
// Force uncombined, if necessary
|
||||
if (!combined)
|
||||
|
@ -189,7 +189,14 @@ void HlslParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memb
|
||||
//
|
||||
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 TBasicType txBasicType = txType.getBasicType();
|
||||
|
||||
const auto selectFormat = [this,&components](TLayoutFormat v1, TLayoutFormat v2, TLayoutFormat v4) -> TLayoutFormat {
|
||||
if (intermediate.getNoStorageFormat())
|
||||
@ -199,7 +206,7 @@ TLayoutFormat HlslParseContext::getLayoutFromTxType(const TSourceLoc& loc, const
|
||||
components == 2 ? v2 : v4;
|
||||
};
|
||||
|
||||
switch (txType.getBasicType()) {
|
||||
switch (txBasicType) {
|
||||
case EbtFloat: return selectFormat(ElfR32f, ElfRg32f, ElfRgba32f);
|
||||
case EbtInt: return selectFormat(ElfR32i, ElfRg32i, ElfRgba32i);
|
||||
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 TType objDerefType(texSampler.type, EvqTemporary, texSampler.vectorSize);
|
||||
TType objDerefType;
|
||||
getTextureReturnType(texSampler, objDerefType);
|
||||
|
||||
if (nodeAsBinary) {
|
||||
TIntermTyped* rhs = nodeAsBinary->getRight();
|
||||
@ -771,7 +779,10 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn
|
||||
} else {
|
||||
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->getSequence().push_back(base);
|
||||
load->getSequence().push_back(index);
|
||||
@ -3292,21 +3303,99 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
if (node == nullptr || !node->getAsOperator())
|
||||
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
|
||||
// Sampler return must always be a vec4, but we can construct a shorter vector or a structure from it.
|
||||
const auto convertReturn = [&loc, &node, this](TIntermTyped* result, const TSampler& sampler) -> TIntermTyped* {
|
||||
result->setType(TType(node->getType().getBasicType(), EvqTemporary, node->getVectorSize()));
|
||||
|
||||
if (sampler.vectorSize < (unsigned)node->getVectorSize()) {
|
||||
// Too many components. Construct shorter vector from it.
|
||||
const TType clampedType(result->getType().getBasicType(), EvqTemporary, sampler.vectorSize);
|
||||
TIntermTyped* convertedResult = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Index into the struct variable to find the member to assign.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
result->setLoc(loc);
|
||||
return result;
|
||||
convertedResult->setLoc(loc);
|
||||
return convertedResult;
|
||||
};
|
||||
|
||||
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(bias); // bias
|
||||
|
||||
node = clampReturn(tex, sampler);
|
||||
node = convertReturn(tex, sampler);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3412,7 +3501,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
|
||||
node = clampReturn(txsample, sampler);
|
||||
node = convertReturn(txsample, sampler);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3445,7 +3534,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
|
||||
node = clampReturn(txsample, sampler);
|
||||
node = convertReturn(txsample, sampler);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3721,7 +3810,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
txfetch->getSequence().push_back(argOffset);
|
||||
}
|
||||
|
||||
node = clampReturn(txfetch, sampler);
|
||||
node = convertReturn(txfetch, sampler);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3752,7 +3841,7 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
|
||||
if (argOffset != nullptr)
|
||||
txsample->getSequence().push_back(argOffset);
|
||||
|
||||
node = clampReturn(txsample, sampler);
|
||||
node = convertReturn(txsample, sampler);
|
||||
|
||||
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
|
||||
TIntermSymbol* HlslParseContext::findTessLinkageSymbol(TBuiltInVariable biType) const
|
||||
{
|
||||
|
@ -213,6 +213,12 @@ public:
|
||||
// Share struct buffer deep types
|
||||
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:
|
||||
struct TFlattenData {
|
||||
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
|
||||
@ -389,6 +395,10 @@ protected:
|
||||
// Structuredbuffer shared types. Typically there are only a few.
|
||||
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;
|
||||
|
||||
// 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