Commit f764fc02 by Shahbaz Youssefi Committed by Commit Bot

Fix varying linking by location

This change breaks the assumption everywhere that varyings can be identified uniquely by name throughout all stages of the pipeline. It further implements linking of varyings by location, if specified. Bug: angleproject:4355 Change-Id: Ie45e48879008c3f0c22d1da3d0d26f37c655e54e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2030026 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 58fc8b11
...@@ -405,13 +405,19 @@ void InitShaderStorageBlockLinker(const ProgramState &state, ShaderStorageBlockL ...@@ -405,13 +405,19 @@ void InitShaderStorageBlockLinker(const ProgramState &state, ShaderStorageBlockL
} }
// Find the matching varying or field by name. // Find the matching varying or field by name.
const sh::ShaderVariable *FindVaryingOrField(const ProgramMergedVaryings &varyings, const sh::ShaderVariable *FindOutputVaryingOrField(const ProgramMergedVaryings &varyings,
ShaderType stage,
const std::string &name) const std::string &name)
{ {
const sh::ShaderVariable *var = nullptr; const sh::ShaderVariable *var = nullptr;
for (const auto &ref : varyings) for (const ProgramVaryingRef &ref : varyings)
{ {
const sh::ShaderVariable *varying = ref.second.get(); if (ref.frontShaderStage != stage)
{
continue;
}
const sh::ShaderVariable *varying = ref.get(stage);
if (varying->name == name) if (varying->name == name)
{ {
var = varying; var = varying;
...@@ -1583,7 +1589,7 @@ angle::Result Program::link(const Context *context) ...@@ -1583,7 +1589,7 @@ angle::Result Program::link(const Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
const auto &mergedVaryings = getMergedVaryings(); const ProgramMergedVaryings &mergedVaryings = getMergedVaryings();
gl::Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex]; gl::Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
if (vertexShader) if (vertexShader)
...@@ -1594,8 +1600,11 @@ angle::Result Program::link(const Context *context) ...@@ -1594,8 +1600,11 @@ angle::Result Program::link(const Context *context)
InitUniformBlockLinker(mState, &resources->uniformBlockLinker); InitUniformBlockLinker(mState, &resources->uniformBlockLinker);
InitShaderStorageBlockLinker(mState, &resources->shaderStorageBlockLinker); InitShaderStorageBlockLinker(mState, &resources->shaderStorageBlockLinker);
ShaderType tfStage = mState.mAttachedShaders[ShaderType::Geometry] ? ShaderType::Geometry
: ShaderType::Vertex;
if (!linkValidateTransformFeedback(context->getClientVersion(), mInfoLog, mergedVaryings, if (!linkValidateTransformFeedback(context->getClientVersion(), mInfoLog, mergedVaryings,
context->getCaps())) tfStage, context->getCaps()))
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1606,7 +1615,7 @@ angle::Result Program::link(const Context *context) ...@@ -1606,7 +1615,7 @@ angle::Result Program::link(const Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
gatherTransformFeedbackVaryings(mergedVaryings); gatherTransformFeedbackVaryings(mergedVaryings, tfStage);
mState.updateTransformFeedbackStrides(); mState.updateTransformFeedbackStrides();
} }
...@@ -4107,6 +4116,7 @@ bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const ...@@ -4107,6 +4116,7 @@ bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
bool Program::linkValidateTransformFeedback(const Version &version, bool Program::linkValidateTransformFeedback(const Version &version,
InfoLog &infoLog, InfoLog &infoLog,
const ProgramMergedVaryings &varyings, const ProgramMergedVaryings &varyings,
ShaderType stage,
const Caps &caps) const const Caps &caps) const
{ {
...@@ -4147,7 +4157,7 @@ bool Program::linkValidateTransformFeedback(const Version &version, ...@@ -4147,7 +4157,7 @@ bool Program::linkValidateTransformFeedback(const Version &version,
std::vector<unsigned int> subscripts; std::vector<unsigned int> subscripts;
std::string baseName = ParseResourceName(tfVaryingName, &subscripts); std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
const sh::ShaderVariable *var = FindVaryingOrField(varyings, baseName); const sh::ShaderVariable *var = FindOutputVaryingOrField(varyings, stage, baseName);
if (var == nullptr) if (var == nullptr)
{ {
infoLog << "Transform feedback varying " << tfVaryingName infoLog << "Transform feedback varying " << tfVaryingName
...@@ -4328,7 +4338,8 @@ bool Program::linkValidateGlobalNames(InfoLog &infoLog) const ...@@ -4328,7 +4338,8 @@ bool Program::linkValidateGlobalNames(InfoLog &infoLog) const
return true; return true;
} }
void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings) void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings,
ShaderType stage)
{ {
// Gather the linked varyings that are used for transform feedback, they should all exist. // Gather the linked varyings that are used for transform feedback, they should all exist.
mState.mLinkedTransformFeedbackVaryings.clear(); mState.mLinkedTransformFeedbackVaryings.clear();
...@@ -4341,9 +4352,14 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi ...@@ -4341,9 +4352,14 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi
{ {
subscript = subscripts.back(); subscript = subscripts.back();
} }
for (const auto &ref : varyings) for (const ProgramVaryingRef &ref : varyings)
{
if (ref.frontShaderStage != stage)
{ {
const sh::ShaderVariable *varying = ref.second.get(); continue;
}
const sh::ShaderVariable *varying = ref.get(stage);
if (baseName == varying->name) if (baseName == varying->name)
{ {
mState.mLinkedTransformFeedbackVaryings.emplace_back( mState.mLinkedTransformFeedbackVaryings.emplace_back(
...@@ -4366,26 +4382,114 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi ...@@ -4366,26 +4382,114 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi
ProgramMergedVaryings Program::getMergedVaryings() const ProgramMergedVaryings Program::getMergedVaryings() const
{ {
ASSERT(mState.mAttachedShaders[ShaderType::Compute] == nullptr);
// Varyings are matched between pairs of consecutive stages, by location if assigned or
// by name otherwise. Note that it's possible for one stage to specify location and the other
// not: https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
// Map stages to the previous active stage in the rendering pipeline. When looking at input
// varyings of a stage, this is used to find the stage whose output varyings are being linked
// with them.
ShaderMap<ShaderType> previousActiveStage;
// Note that kAllGraphicsShaderTypes is sorted according to the rendering pipeline.
ShaderType lastActiveStage = ShaderType::InvalidEnum;
for (ShaderType stage : kAllGraphicsShaderTypes)
{
previousActiveStage[stage] = lastActiveStage;
if (mState.mAttachedShaders[stage])
{
lastActiveStage = stage;
}
}
// First, go through output varyings and create two maps (one by name, one by location) for
// faster lookup when matching input varyings.
ShaderMap<std::map<std::string, size_t>> outputVaryingNameToIndex;
ShaderMap<std::map<int, size_t>> outputVaryingLocationToIndex;
ProgramMergedVaryings merged; ProgramMergedVaryings merged;
// Gather output varyings.
for (Shader *shader : mState.mAttachedShaders) for (Shader *shader : mState.mAttachedShaders)
{ {
if (shader) if (!shader)
{ {
ShaderType shaderType = shader->getType(); continue;
}
ShaderType stage = shader->getType();
for (const sh::ShaderVariable &varying : shader->getOutputVaryings()) for (const sh::ShaderVariable &varying : shader->getOutputVaryings())
{ {
ProgramVaryingRef *ref = &merged[varying.name]; merged.push_back({});
ProgramVaryingRef *ref = &merged.back();
ref->frontShader = &varying; ref->frontShader = &varying;
ref->frontShaderStage = shaderType; ref->frontShaderStage = stage;
// Always map by name. Even if location is provided in this stage, it may not be in the
// paired stage.
outputVaryingNameToIndex[stage][varying.name] = merged.size() - 1;
// If location is provided, also keep it in a map by location.
if (varying.location != -1)
{
outputVaryingLocationToIndex[stage][varying.location] = merged.size() - 1;
}
}
}
// Gather input varyings, and match them with output varyings of the previous stage.
for (Shader *shader : mState.mAttachedShaders)
{
if (!shader)
{
continue;
} }
ShaderType stage = shader->getType();
ShaderType previousStage = previousActiveStage[stage];
for (const sh::ShaderVariable &varying : shader->getInputVaryings()) for (const sh::ShaderVariable &varying : shader->getInputVaryings())
{ {
ProgramVaryingRef *ref = &merged[varying.name]; size_t mergedIndex = merged.size();
ref->backShader = &varying; if (previousStage != ShaderType::InvalidEnum)
ref->backShaderStage = shaderType; {
// If location is provided, see if we can match by location.
if (varying.location != -1)
{
auto byLocationIter =
outputVaryingLocationToIndex[previousStage].find(varying.location);
if (byLocationIter != outputVaryingLocationToIndex[previousStage].end())
{
mergedIndex = byLocationIter->second;
}
}
// If not found, try to match by name.
if (mergedIndex == merged.size())
{
auto byNameIter = outputVaryingNameToIndex[previousStage].find(varying.name);
if (byNameIter != outputVaryingNameToIndex[previousStage].end())
{
mergedIndex = byNameIter->second;
}
} }
} }
// If no previous stage, or not matched by location or name, create a new entry for it.
if (mergedIndex == merged.size())
{
merged.push_back({});
mergedIndex = merged.size() - 1;
}
ProgramVaryingRef *ref = &merged[mergedIndex];
ref->backShader = &varying;
ref->backShaderStage = stage;
}
} }
return merged; return merged;
......
...@@ -568,7 +568,13 @@ class ProgramAliasedBindings final : angle::NonCopyable ...@@ -568,7 +568,13 @@ class ProgramAliasedBindings final : angle::NonCopyable
struct ProgramVaryingRef struct ProgramVaryingRef
{ {
const sh::ShaderVariable *get() const { return frontShader ? frontShader : backShader; } const sh::ShaderVariable *get(ShaderType stage) const
{
ASSERT(stage == frontShaderStage || stage == backShaderStage);
const sh::ShaderVariable *ref = stage == frontShaderStage ? frontShader : backShader;
ASSERT(ref);
return ref;
}
const sh::ShaderVariable *frontShader = nullptr; const sh::ShaderVariable *frontShader = nullptr;
const sh::ShaderVariable *backShader = nullptr; const sh::ShaderVariable *backShader = nullptr;
...@@ -576,7 +582,7 @@ struct ProgramVaryingRef ...@@ -576,7 +582,7 @@ struct ProgramVaryingRef
ShaderType backShaderStage = ShaderType::InvalidEnum; ShaderType backShaderStage = ShaderType::InvalidEnum;
}; };
using ProgramMergedVaryings = std::map<std::string, ProgramVaryingRef>; using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
class Program final : angle::NonCopyable, public LabeledObject class Program final : angle::NonCopyable, public LabeledObject
{ {
...@@ -1025,10 +1031,11 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -1025,10 +1031,11 @@ class Program final : angle::NonCopyable, public LabeledObject
bool linkValidateTransformFeedback(const Version &version, bool linkValidateTransformFeedback(const Version &version,
InfoLog &infoLog, InfoLog &infoLog,
const ProgramMergedVaryings &linkedVaryings, const ProgramMergedVaryings &linkedVaryings,
ShaderType stage,
const Caps &caps) const; const Caps &caps) const;
bool linkValidateGlobalNames(InfoLog &infoLog) const; bool linkValidateGlobalNames(InfoLog &infoLog) const;
void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings); void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings, ShaderType stage);
ProgramMergedVaryings getMergedVaryings() const; ProgramMergedVaryings getMergedVaryings() const;
int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const; int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const;
......
...@@ -28,47 +28,65 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) ...@@ -28,47 +28,65 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
// non-array shader variable 'vx' or 'vy' for actual comparison instead. // non-array shader variable 'vx' or 'vy' for actual comparison instead.
sh::ShaderVariable vx, vy; sh::ShaderVariable vx, vy;
const sh::ShaderVariable *px, *py; const sh::ShaderVariable *px, *py;
px = &x.varying();
py = &y.varying();
if (x.isArrayElement()) if (x.isArrayElement())
{ {
vx = *x.varying; vx = *px;
vx.arraySizes.clear(); vx.arraySizes.clear();
px = &vx; px = &vx;
} }
else
{
px = x.varying;
}
if (y.isArrayElement()) if (y.isArrayElement())
{ {
vy = *y.varying; vy = *py;
vy.arraySizes.clear(); vy.arraySizes.clear();
py = &vy; py = &vy;
} }
else
{
py = y.varying;
}
return gl::CompareShaderVar(*px, *py); return gl::CompareShaderVar(*px, *py);
} }
} // anonymous namespace } // anonymous namespace
// Implementation of VaryingInShaderRef
VaryingInShaderRef::VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn)
: varying(varyingIn), stage(stageIn)
{}
VaryingInShaderRef::~VaryingInShaderRef() = default;
VaryingInShaderRef::VaryingInShaderRef(VaryingInShaderRef &&other)
{
*this = std::move(other);
}
VaryingInShaderRef &VaryingInShaderRef::operator=(VaryingInShaderRef &&other)
{
std::swap(varying, other.varying);
std::swap(stage, other.stage);
std::swap(parentStructName, other.parentStructName);
std::swap(parentStructMappedName, other.parentStructMappedName);
return *this;
}
// Implementation of PackedVarying // Implementation of PackedVarying
PackedVarying::PackedVarying(const sh::ShaderVariable &varyingIn, PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
VaryingInShaderRef &&backVaryingIn,
sh::InterpolationType interpolationIn) sh::InterpolationType interpolationIn)
: PackedVarying(varyingIn, interpolationIn, "", "", false) : PackedVarying(std::move(frontVaryingIn), std::move(backVaryingIn), interpolationIn, 0)
{} {}
PackedVarying::PackedVarying(const sh::ShaderVariable &varyingIn,
PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
VaryingInShaderRef &&backVaryingIn,
sh::InterpolationType interpolationIn, sh::InterpolationType interpolationIn,
const std::string &parentStructNameIn,
const std::string &parentStructMappedNameIn,
GLuint fieldIndexIn) GLuint fieldIndexIn)
: varying(&varyingIn), : frontVarying(std::move(frontVaryingIn)),
backVarying(std::move(backVaryingIn)),
interpolation(interpolationIn), interpolation(interpolationIn),
parentStructName(parentStructNameIn),
parentStructMappedName(parentStructMappedNameIn),
arrayIndex(GL_INVALID_INDEX), arrayIndex(GL_INVALID_INDEX),
fieldIndex(fieldIndexIn) fieldIndex(fieldIndexIn)
{} {}
...@@ -76,17 +94,17 @@ PackedVarying::PackedVarying(const sh::ShaderVariable &varyingIn, ...@@ -76,17 +94,17 @@ PackedVarying::PackedVarying(const sh::ShaderVariable &varyingIn,
PackedVarying::~PackedVarying() = default; PackedVarying::~PackedVarying() = default;
PackedVarying::PackedVarying(PackedVarying &&other) PackedVarying::PackedVarying(PackedVarying &&other)
: PackedVarying(*other.varying, other.interpolation) : frontVarying(other.frontVarying.stage, other.frontVarying.varying),
backVarying(other.backVarying.stage, other.backVarying.varying)
{ {
*this = std::move(other); *this = std::move(other);
} }
PackedVarying &PackedVarying::operator=(PackedVarying &&other) PackedVarying &PackedVarying::operator=(PackedVarying &&other)
{ {
std::swap(varying, other.varying); std::swap(frontVarying, other.frontVarying);
std::swap(shaderStages, other.shaderStages); std::swap(backVarying, other.backVarying);
std::swap(interpolation, other.interpolation); std::swap(interpolation, other.interpolation);
std::swap(parentStructName, other.parentStructName);
std::swap(parentStructMappedName, other.parentStructMappedName);
std::swap(arrayIndex, other.arrayIndex); std::swap(arrayIndex, other.arrayIndex);
std::swap(fieldIndex, other.fieldIndex); std::swap(fieldIndex, other.fieldIndex);
...@@ -106,7 +124,7 @@ VaryingPacking::~VaryingPacking() = default; ...@@ -106,7 +124,7 @@ VaryingPacking::~VaryingPacking() = default;
// Returns false if unsuccessful. // Returns false if unsuccessful.
bool VaryingPacking::packVarying(const PackedVarying &packedVarying) bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
{ {
const sh::ShaderVariable &varying = *packedVarying.varying; const sh::ShaderVariable &varying = packedVarying.varying();
// "Non - square matrices of type matCxR consume the same space as a square matrix of type matN // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN
// where N is the greater of C and R." // where N is the greater of C and R."
...@@ -234,7 +252,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -234,7 +252,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
registerInfo.varyingRowIndex = 0; registerInfo.varyingRowIndex = 0;
// Do not record register info for builtins. // Do not record register info for builtins.
// TODO(jmadill): Clean this up. // TODO(jmadill): Clean this up.
if (!packedVarying.varying->isBuiltIn()) if (!varying.isBuiltIn())
{ {
mRegisterList.push_back(registerInfo); mRegisterList.push_back(registerInfo);
} }
...@@ -277,7 +295,7 @@ void VaryingPacking::insert(unsigned int registerRow, ...@@ -277,7 +295,7 @@ void VaryingPacking::insert(unsigned int registerRow,
unsigned int varyingRows = 0; unsigned int varyingRows = 0;
unsigned int varyingColumns = 0; unsigned int varyingColumns = 0;
const auto &varying = *packedVarying.varying; const sh::ShaderVariable &varying = packedVarying.varying();
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
GLenum transposedType = gl::TransposeMatrixType(varying.type); GLenum transposedType = gl::TransposeMatrixType(varying.type);
varyingRows = gl::VariableRowCount(transposedType); varyingRows = gl::VariableRowCount(transposedType);
...@@ -303,7 +321,7 @@ void VaryingPacking::insert(unsigned int registerRow, ...@@ -303,7 +321,7 @@ void VaryingPacking::insert(unsigned int registerRow,
registerInfo.varyingArrayIndex = arrayElement; registerInfo.varyingArrayIndex = arrayElement;
// Do not record register info for builtins. // Do not record register info for builtins.
// TODO(jmadill): Clean this up. // TODO(jmadill): Clean this up.
if (!packedVarying.varying->isBuiltIn()) if (!varying.isBuiltIn())
{ {
mRegisterList.push_back(registerInfo); mRegisterList.push_back(registerInfo);
} }
...@@ -316,26 +334,114 @@ void VaryingPacking::insert(unsigned int registerRow, ...@@ -316,26 +334,114 @@ void VaryingPacking::insert(unsigned int registerRow,
} }
} }
bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, void VaryingPacking::packUserVarying(const ProgramVaryingRef &ref,
const ProgramMergedVaryings &mergedVaryings, VaryingUniqueFullNames *uniqueFullNames)
const std::vector<std::string> &tfVaryings)
{ {
std::set<std::string> uniqueFullNames; const sh::ShaderVariable *input = ref.frontShader;
mPackedVaryings.clear(); const sh::ShaderVariable *output = ref.backShader;
mInputVaryings.clear();
// Will get the vertex shader interpolation by default.
sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
for (const auto &ref : mergedVaryings) VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
VaryingInShaderRef backVarying(ref.backShaderStage, output);
mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation);
if (input)
{
(*uniqueFullNames)[ref.frontShaderStage].insert(
mPackedVaryings.back().fullName(ref.frontShaderStage));
}
if (output)
{ {
const sh::ShaderVariable *input = ref.second.frontShader; (*uniqueFullNames)[ref.backShaderStage].insert(
const sh::ShaderVariable *output = ref.second.backShader; mPackedVaryings.back().fullName(ref.backShaderStage));
}
}
void VaryingPacking::packUserVaryingField(const ProgramVaryingRef &ref,
GLuint fieldIndex,
VaryingUniqueFullNames *uniqueFullNames)
{
const sh::ShaderVariable *input = ref.frontShader;
const sh::ShaderVariable *output = ref.backShader;
// Will get the vertex shader interpolation by default.
sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
const sh::ShaderVariable *frontField = input ? &input->fields[fieldIndex] : nullptr;
const sh::ShaderVariable *backField = output ? &output->fields[fieldIndex] : nullptr;
VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
VaryingInShaderRef backVarying(ref.backShaderStage, backField);
if (input) if (input)
{ {
mInputVaryings.emplace_back(*input); ASSERT(!frontField->isStruct() && !frontField->isArray());
frontVarying.parentStructName = input->name;
frontVarying.parentStructMappedName = input->mappedName;
}
if (output)
{
ASSERT(!backField->isStruct() && !backField->isArray());
backVarying.parentStructName = output->name;
backVarying.parentStructMappedName = output->mappedName;
}
mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation,
fieldIndex);
if (input)
{
(*uniqueFullNames)[ref.frontShaderStage].insert(
mPackedVaryings.back().fullName(ref.frontShaderStage));
}
if (output)
{
(*uniqueFullNames)[ref.backShaderStage].insert(
mPackedVaryings.back().fullName(ref.backShaderStage));
} }
}
void VaryingPacking::packUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript)
{
const sh::ShaderVariable *input = ref.frontShader;
VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
input->interpolation);
mPackedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
}
void VaryingPacking::packUserVaryingFieldTF(const ProgramVaryingRef &ref,
const sh::ShaderVariable &field,
GLuint fieldIndex)
{
const sh::ShaderVariable *input = ref.frontShader;
VaryingInShaderRef frontVarying(ref.frontShaderStage, &field);
VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
frontVarying.parentStructName = input->name;
frontVarying.parentStructMappedName = input->mappedName;
ShaderBitSet shaderStages; mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
shaderStages.set(ref.second.frontShaderStage); input->interpolation, fieldIndex);
shaderStages.set(ref.second.backShaderStage); }
bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings)
{
VaryingUniqueFullNames uniqueFullNames;
mPackedVaryings.clear();
for (const ProgramVaryingRef &ref : mergedVaryings)
{
const sh::ShaderVariable *input = ref.frontShader;
const sh::ShaderVariable *output = ref.backShader;
// Only pack statically used varyings that have a matched input or output, plus special // Only pack statically used varyings that have a matched input or output, plus special
// builtins. Note that we pack all statically used user-defined varyings even if they are // builtins. Note that we pack all statically used user-defined varyings even if they are
...@@ -353,31 +459,26 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -353,31 +459,26 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
!(varying->name == "gl_PointSize" && !(varying->name == "gl_PointSize" &&
mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)) mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9))
{ {
// Will get the vertex shader interpolation by default.
auto interpolation = ref.second.get()->interpolation;
// Note that we lose the vertex shader static use information here. The data for the
// variable is taken from the fragment shader.
if (varying->isStruct()) if (varying->isStruct())
{ {
ASSERT(!(varying->isArray() && varying == input)); ASSERT(!(varying->isArray() && varying == input));
for (GLuint fieldIndex = 0; fieldIndex < varying->fields.size(); ++fieldIndex) for (GLuint fieldIndex = 0; fieldIndex < varying->fields.size(); ++fieldIndex)
{ {
const sh::ShaderVariable &field = varying->fields[fieldIndex]; packUserVaryingField(ref, fieldIndex, &uniqueFullNames);
}
ASSERT(!field.isStruct() && !field.isArray()); if (input)
mPackedVaryings.emplace_back(field, interpolation, varying->name, {
varying->mappedName, fieldIndex); uniqueFullNames[ref.frontShaderStage].insert(input->name);
mPackedVaryings.back().shaderStages = shaderStages; }
uniqueFullNames.insert(mPackedVaryings.back().fullName()); if (output)
{
uniqueFullNames[ref.backShaderStage].insert(output->name);
} }
uniqueFullNames.insert(varying->name);
} }
else else
{ {
mPackedVaryings.emplace_back(*varying, interpolation); packUserVarying(ref, &uniqueFullNames);
mPackedVaryings.back().shaderStages = shaderStages;
uniqueFullNames.insert(mPackedVaryings.back().fullName());
} }
continue; continue;
} }
...@@ -386,7 +487,7 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -386,7 +487,7 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
// If the varying is not used in the input, we know it is inactive. // If the varying is not used in the input, we know it is inactive.
if (!input) if (!input)
{ {
mInactiveVaryingMappedNames.push_back(output->mappedName); mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
continue; continue;
} }
...@@ -401,7 +502,8 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -401,7 +502,8 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
subscript = subscripts.back(); subscript = subscripts.back();
} }
// Already packed for fragment shader. // Already packed for fragment shader.
if (uniqueFullNames.count(tfVarying) > 0 || uniqueFullNames.count(baseName) > 0) if (uniqueFullNames[ref.frontShaderStage].count(tfVarying) > 0 ||
uniqueFullNames[ref.frontShaderStage].count(baseName) > 0)
{ {
continue; continue;
} }
...@@ -413,13 +515,11 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -413,13 +515,11 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
if (field != nullptr) if (field != nullptr)
{ {
ASSERT(!field->isStruct() && !field->isArray()); ASSERT(!field->isStruct() && !field->isArray());
mPackedVaryings.emplace_back(*field, input->interpolation, input->name,
input->mappedName, fieldIndex); packUserVaryingFieldTF(ref, *field, fieldIndex);
mPackedVaryings.back().shaderStages.set(ShaderType::Vertex); uniqueFullNames[ref.frontShaderStage].insert(tfVarying);
mPackedVaryings.back().arrayIndex = GL_INVALID_INDEX;
uniqueFullNames.insert(tfVarying);
} }
uniqueFullNames.insert(input->name); uniqueFullNames[ref.frontShaderStage].insert(input->name);
} }
// Array as a whole and array element conflict has already been checked in // Array as a whole and array element conflict has already been checked in
// linkValidateTransformFeedback. // linkValidateTransformFeedback.
...@@ -428,10 +528,8 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -428,10 +528,8 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
// only pack varyings that are not builtins. // only pack varyings that are not builtins.
if (tfVarying.compare(0, 3, "gl_") != 0) if (tfVarying.compare(0, 3, "gl_") != 0)
{ {
mPackedVaryings.emplace_back(*input, input->interpolation); packUserVaryingTF(ref, subscript);
mPackedVaryings.back().shaderStages.set(ShaderType::Vertex); uniqueFullNames[ref.frontShaderStage].insert(tfVarying);
mPackedVaryings.back().arrayIndex = static_cast<GLuint>(subscript);
uniqueFullNames.insert(tfVarying);
} }
// Continue to match next array element for 'input' if the current match is array // Continue to match next array element for 'input' if the current match is array
// element. // element.
...@@ -442,9 +540,13 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -442,9 +540,13 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
} }
} }
if (uniqueFullNames.count(ref.first) == 0) if (input && uniqueFullNames[ref.frontShaderStage].count(input->name) == 0)
{
mInactiveVaryingMappedNames[ref.frontShaderStage].push_back(input->mappedName);
}
if (output && uniqueFullNames[ref.backShaderStage].count(output->name) == 0)
{ {
mInactiveVaryingMappedNames.push_back(input->mappedName); mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
} }
} }
...@@ -463,7 +565,10 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -463,7 +565,10 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
{ {
if (!packVarying(packedVarying)) if (!packVarying(packedVarying))
{ {
infoLog << "Could not pack varying " << packedVarying.fullName(); ShaderType eitherStage = packedVarying.frontVarying.varying
? packedVarying.frontVarying.stage
: packedVarying.backVarying.stage;
infoLog << "Could not pack varying " << packedVarying.fullName(eitherStage);
// TODO(jmadill): Implement more sophisticated component packing in D3D9. // TODO(jmadill): Implement more sophisticated component packing in D3D9.
if (mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9) if (mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
......
...@@ -25,34 +25,77 @@ namespace gl ...@@ -25,34 +25,77 @@ namespace gl
class InfoLog; class InfoLog;
struct ProgramVaryingRef; struct ProgramVaryingRef;
using ProgramMergedVaryings = std::map<std::string, ProgramVaryingRef>; using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
// A varying can have different names between stages if matched by the location layout qualifier.
// Additionally, same name varyings could still be of two identical struct types with different
// names. This struct contains information on the varying in one of the two stages. PackedVarying
// will thus contain two copies of this along with common information, such as interpolation or
// field index.
struct VaryingInShaderRef : angle::NonCopyable
{
VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn);
VaryingInShaderRef(VaryingInShaderRef &&other);
~VaryingInShaderRef();
VaryingInShaderRef &operator=(VaryingInShaderRef &&other);
const sh::ShaderVariable *varying;
ShaderType stage;
// Struct name
std::string parentStructName;
std::string parentStructMappedName;
};
struct PackedVarying : angle::NonCopyable struct PackedVarying : angle::NonCopyable
{ {
PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn); // Throughout this file, the "front" stage refers to the stage that outputs the varying, and the
PackedVarying(const sh::ShaderVariable &varyingIn, // "back" stage refers to the stage that takes the varying as input. Note that this struct
// contains linked varyings, which means both front and back stage varyings are valid, except
// for the following which may have only one valid stage.
//
// - transform-feedback-captured varyings
// - builtins
// - separable program stages,
//
PackedVarying(VaryingInShaderRef &&frontVaryingIn,
VaryingInShaderRef &&backVaryingIn,
sh::InterpolationType interpolationIn);
PackedVarying(VaryingInShaderRef &&frontVaryingIn,
VaryingInShaderRef &&backVaryingIn,
sh::InterpolationType interpolationIn, sh::InterpolationType interpolationIn,
const std::string &parentStructNameIn,
const std::string &parentStructMappedNameIn,
GLuint fieldIndexIn); GLuint fieldIndexIn);
PackedVarying(PackedVarying &&other); PackedVarying(PackedVarying &&other);
~PackedVarying(); ~PackedVarying();
PackedVarying &operator=(PackedVarying &&other); PackedVarying &operator=(PackedVarying &&other);
bool isStructField() const { return !parentStructName.empty(); } bool isStructField() const { return !frontVarying.parentStructName.empty(); }
bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; } bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; }
std::string fullName() const // Return either front or back varying, whichever is available. Only used when the name of the
// varying is not important, but only the type is interesting.
const sh::ShaderVariable &varying() const
{
return frontVarying.varying ? *frontVarying.varying : *backVarying.varying;
}
std::string fullName(ShaderType stage) const
{ {
ASSERT(stage == frontVarying.stage || stage == backVarying.stage);
const VaryingInShaderRef &varying =
stage == frontVarying.stage ? frontVarying : backVarying;
std::stringstream fullNameStr; std::stringstream fullNameStr;
if (isStructField()) if (isStructField())
{ {
fullNameStr << parentStructName << "."; fullNameStr << varying.parentStructName << ".";
} }
fullNameStr << varying->name; fullNameStr << varying.varying->name;
if (arrayIndex != GL_INVALID_INDEX) if (arrayIndex != GL_INVALID_INDEX)
{ {
fullNameStr << "[" << arrayIndex << "]"; fullNameStr << "[" << arrayIndex << "]";
...@@ -63,22 +106,15 @@ struct PackedVarying : angle::NonCopyable ...@@ -63,22 +106,15 @@ struct PackedVarying : angle::NonCopyable
// Transform feedback varyings can be only referenced in the VS. // Transform feedback varyings can be only referenced in the VS.
bool vertexOnly() const bool vertexOnly() const
{ {
ShaderBitSet vertex; return frontVarying.stage == ShaderType::Vertex && backVarying.varying == nullptr;
vertex.set(ShaderType::Vertex);
return shaderStages == vertex;
} }
const sh::ShaderVariable *varying; VaryingInShaderRef frontVarying;
VaryingInShaderRef backVarying;
ShaderBitSet shaderStages;
// Cached so we can store sh::ShaderVariable to point to varying fields. // Cached so we can store sh::ShaderVariable to point to varying fields.
sh::InterpolationType interpolation; sh::InterpolationType interpolation;
// Struct name
std::string parentStructName;
std::string parentStructMappedName;
GLuint arrayIndex; GLuint arrayIndex;
// Field index in the struct. In Vulkan, this is used to assign a // Field index in the struct. In Vulkan, this is used to assign a
...@@ -112,14 +148,7 @@ struct PackedVaryingRegister final ...@@ -112,14 +148,7 @@ struct PackedVaryingRegister final
std::string tfVaryingName() const std::string tfVaryingName() const
{ {
if (packedVarying->isArrayElement() || packedVarying->isStructField()) return packedVarying->fullName(packedVarying->frontVarying.stage);
{
return packedVarying->fullName();
}
else
{
return packedVarying->varying->name;
}
} }
// Index to the array of varyings. // Index to the array of varyings.
...@@ -182,13 +211,11 @@ class VaryingPacking final : angle::NonCopyable ...@@ -182,13 +211,11 @@ class VaryingPacking final : angle::NonCopyable
return static_cast<unsigned int>(mRegisterList.size()); return static_cast<unsigned int>(mRegisterList.size());
} }
const std::vector<std::string> &getInactiveVaryingMappedNames() const const ShaderMap<std::vector<std::string>> &getInactiveVaryingMappedNames() const
{ {
return mInactiveVaryingMappedNames; return mInactiveVaryingMappedNames;
} }
const std::vector<sh::ShaderVariable> &getInputVaryings() const { return mInputVaryings; }
private: private:
bool packVarying(const PackedVarying &packedVarying); bool packVarying(const PackedVarying &packedVarying);
bool isFree(unsigned int registerRow, bool isFree(unsigned int registerRow,
...@@ -199,11 +226,20 @@ class VaryingPacking final : angle::NonCopyable ...@@ -199,11 +226,20 @@ class VaryingPacking final : angle::NonCopyable
unsigned int registerColumn, unsigned int registerColumn,
const PackedVarying &packedVarying); const PackedVarying &packedVarying);
using VaryingUniqueFullNames = ShaderMap<std::set<std::string>>;
void packUserVarying(const ProgramVaryingRef &ref, VaryingUniqueFullNames *uniqueFullNames);
void packUserVaryingField(const ProgramVaryingRef &ref,
GLuint fieldIndex,
VaryingUniqueFullNames *uniqueFullNames);
void packUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript);
void packUserVaryingFieldTF(const ProgramVaryingRef &ref,
const sh::ShaderVariable &field,
GLuint fieldIndex);
std::vector<Register> mRegisterMap; std::vector<Register> mRegisterMap;
std::vector<PackedVaryingRegister> mRegisterList; std::vector<PackedVaryingRegister> mRegisterList;
std::vector<sh::ShaderVariable> mInputVaryings;
std::vector<PackedVarying> mPackedVaryings; std::vector<PackedVarying> mPackedVaryings;
std::vector<std::string> mInactiveVaryingMappedNames; ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames;
PackMode mPackMode; PackMode mPackMode;
}; };
......
...@@ -30,9 +30,11 @@ class VaryingPackingTest : public ::testing::TestWithParam<GLuint> ...@@ -30,9 +30,11 @@ class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
VaryingPacking *varyingPacking) VaryingPacking *varyingPacking)
{ {
std::vector<PackedVarying> packedVaryings; std::vector<PackedVarying> packedVaryings;
for (const auto &shVarying : shVaryings) for (const sh::ShaderVariable &shVarying : shVaryings)
{ {
packedVaryings.push_back(PackedVarying(shVarying, shVarying.interpolation)); packedVaryings.push_back(PackedVarying(
VaryingInShaderRef(ShaderType::Vertex, &shVarying),
VaryingInShaderRef(ShaderType::Fragment, &shVarying), shVarying.interpolation));
} }
InfoLog infoLog; InfoLog infoLog;
......
...@@ -414,7 +414,7 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking, ...@@ -414,7 +414,7 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking,
for (GLuint registerIndex = 0u; registerIndex < registerInfos.size(); ++registerIndex) for (GLuint registerIndex = 0u; registerIndex < registerInfos.size(); ++registerIndex)
{ {
const PackedVaryingRegister &registerInfo = registerInfos[registerIndex]; const PackedVaryingRegister &registerInfo = registerInfos[registerIndex];
const auto &varying = *registerInfo.packedVarying->varying; const auto &varying = registerInfo.packedVarying->varying();
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
// TODO: Add checks to ensure D3D interpolation modifiers don't result in too many // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
...@@ -599,14 +599,15 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps, ...@@ -599,14 +599,15 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps,
{ {
const PackedVaryingRegister &registerInfo = registerInfos[registerIndex]; const PackedVaryingRegister &registerInfo = registerInfos[registerIndex];
const auto &packedVarying = *registerInfo.packedVarying; const auto &packedVarying = *registerInfo.packedVarying;
const auto &varying = *packedVarying.varying; const auto &varying = *packedVarying.frontVarying.varying;
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
vertexGenerateOutput << " output.v" << registerIndex << " = "; vertexGenerateOutput << " output.v" << registerIndex << " = ";
if (packedVarying.isStructField()) if (packedVarying.isStructField())
{ {
vertexGenerateOutput << DecorateVariable(packedVarying.parentStructName) << "."; vertexGenerateOutput << DecorateVariable(packedVarying.frontVarying.parentStructName)
<< ".";
} }
vertexGenerateOutput << DecorateVariable(varying.name); vertexGenerateOutput << DecorateVariable(varying.name);
...@@ -798,19 +799,28 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps, ...@@ -798,19 +799,28 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps,
{ {
const PackedVaryingRegister &registerInfo = registerInfos[registerIndex]; const PackedVaryingRegister &registerInfo = registerInfos[registerIndex];
const auto &packedVarying = *registerInfo.packedVarying; const auto &packedVarying = *registerInfo.packedVarying;
const auto &varying = *packedVarying.varying;
// Don't reference VS-only transform feedback varyings in the PS.
if (packedVarying.vertexOnly())
{
continue;
}
const auto &varying = *packedVarying.backVarying.varying;
ASSERT(!varying.isBuiltIn() && !varying.isStruct()); ASSERT(!varying.isBuiltIn() && !varying.isStruct());
// Don't reference VS-only transform feedback varyings in the PS. Note that we're relying on // Note that we're relying on that the active flag is set according to usage in the fragment
// that the active flag is set according to usage in the fragment shader. // shader.
if (packedVarying.vertexOnly() || !varying.active) if (!varying.active)
{
continue; continue;
}
pixelPrologue << " "; pixelPrologue << " ";
if (packedVarying.isStructField()) if (packedVarying.isStructField())
{ {
pixelPrologue << DecorateVariable(packedVarying.parentStructName) << "."; pixelPrologue << DecorateVariable(packedVarying.backVarying.parentStructName) << ".";
} }
pixelPrologue << DecorateVariable(varying.name); pixelPrologue << DecorateVariable(varying.name);
......
...@@ -3141,7 +3141,7 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi ...@@ -3141,7 +3141,7 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyi
for (GLuint registerIndex = 0u; registerIndex < registerInfos.size(); ++registerIndex) for (GLuint registerIndex = 0u; registerIndex < registerInfos.size(); ++registerIndex)
{ {
const auto &registerInfo = registerInfos[registerIndex]; const auto &registerInfo = registerInfos[registerIndex];
const auto &varying = *registerInfo.packedVarying->varying; const auto &varying = registerInfo.packedVarying->varying();
GLenum transposedType = gl::TransposeMatrixType(varying.type); GLenum transposedType = gl::TransposeMatrixType(varying.type);
int componentCount = gl::VariableColumnCount(transposedType); int componentCount = gl::VariableColumnCount(transposedType);
ASSERT(!varying.isBuiltIn() && !varying.isStruct()); ASSERT(!varying.isBuiltIn() && !varying.isStruct());
......
...@@ -237,23 +237,20 @@ ShaderInterfaceVariableInfo *AddLocationInfo(ShaderInterfaceVariableInfoMap *inf ...@@ -237,23 +237,20 @@ ShaderInterfaceVariableInfo *AddLocationInfo(ShaderInterfaceVariableInfoMap *inf
const std::string &varName, const std::string &varName,
uint32_t location, uint32_t location,
uint32_t component, uint32_t component,
gl::ShaderBitSet activeStages) gl::ShaderType stage)
{ {
// The info map for this name may or may not exist already. This function merges the // The info map for this name may or may not exist already. This function merges the
// location/component information. // location/component information.
ShaderInterfaceVariableInfo *info = &(*infoMap)[varName]; ShaderInterfaceVariableInfo *info = &(*infoMap)[varName];
for (const gl::ShaderType shaderType : activeStages)
{
ASSERT(info->descriptorSet == ShaderInterfaceVariableInfo::kInvalid); ASSERT(info->descriptorSet == ShaderInterfaceVariableInfo::kInvalid);
ASSERT(info->binding == ShaderInterfaceVariableInfo::kInvalid); ASSERT(info->binding == ShaderInterfaceVariableInfo::kInvalid);
ASSERT(info->location[shaderType] == ShaderInterfaceVariableInfo::kInvalid); ASSERT(info->location[stage] == ShaderInterfaceVariableInfo::kInvalid);
ASSERT(info->component[shaderType] == ShaderInterfaceVariableInfo::kInvalid); ASSERT(info->component[stage] == ShaderInterfaceVariableInfo::kInvalid);
info->location[shaderType] = location; info->location[stage] = location;
info->component[shaderType] = component; info->component[stage] = component;
} info->activeStages.set(stage);
info->activeStages |= activeStages;
return info; return info;
} }
...@@ -489,16 +486,13 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt ...@@ -489,16 +486,13 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt
void AssignAttributeLocations(const gl::ProgramState &programState, void AssignAttributeLocations(const gl::ProgramState &programState,
ShaderInterfaceVariableInfoMap *variableInfoMapOut) ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{ {
gl::ShaderBitSet vertexOnly;
vertexOnly.set(gl::ShaderType::Vertex);
// Assign attribute locations for the vertex shader. // Assign attribute locations for the vertex shader.
for (const sh::ShaderVariable &attribute : programState.getProgramInputs()) for (const sh::ShaderVariable &attribute : programState.getProgramInputs())
{ {
ASSERT(attribute.active); ASSERT(attribute.active);
AddLocationInfo(variableInfoMapOut, attribute.mappedName, attribute.location, AddLocationInfo(variableInfoMapOut, attribute.mappedName, attribute.location,
ShaderInterfaceVariableInfo::kInvalid, vertexOnly); ShaderInterfaceVariableInfo::kInvalid, gl::ShaderType::Vertex);
} }
} }
...@@ -512,9 +506,6 @@ void AssignOutputLocations(const gl::ProgramState &programState, ...@@ -512,9 +506,6 @@ void AssignOutputLocations(const gl::ProgramState &programState,
const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask", const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask",
"gl_FragStencilRefARB"}; "gl_FragStencilRefARB"};
gl::ShaderBitSet fragmentOnly;
fragmentOnly.set(gl::ShaderType::Fragment);
for (const gl::VariableLocation &outputLocation : outputLocations) for (const gl::VariableLocation &outputLocation : outputLocations)
{ {
if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored) if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
...@@ -536,7 +527,7 @@ void AssignOutputLocations(const gl::ProgramState &programState, ...@@ -536,7 +527,7 @@ void AssignOutputLocations(const gl::ProgramState &programState,
} }
AddLocationInfo(variableInfoMapOut, outputVar.mappedName, location, AddLocationInfo(variableInfoMapOut, outputVar.mappedName, location,
ShaderInterfaceVariableInfo::kInvalid, fragmentOnly); ShaderInterfaceVariableInfo::kInvalid, gl::ShaderType::Fragment);
} }
} }
...@@ -545,8 +536,8 @@ void AssignOutputLocations(const gl::ProgramState &programState, ...@@ -545,8 +536,8 @@ void AssignOutputLocations(const gl::ProgramState &programState,
// location 0 to these entries, adding an entry for them here allows us to ASSERT that every // location 0 to these entries, adding an entry for them here allows us to ASSERT that every
// shader interface variable is processed during the SPIR-V transformation. This is done when // shader interface variable is processed during the SPIR-V transformation. This is done when
// iterating the ids provided by OpEntryPoint. // iterating the ids provided by OpEntryPoint.
AddLocationInfo(variableInfoMapOut, "webgl_FragColor", 0, 0, fragmentOnly); AddLocationInfo(variableInfoMapOut, "webgl_FragColor", 0, 0, gl::ShaderType::Fragment);
AddLocationInfo(variableInfoMapOut, "webgl_FragData", 0, 0, fragmentOnly); AddLocationInfo(variableInfoMapOut, "webgl_FragData", 0, 0, gl::ShaderType::Fragment);
} }
void AssignVaryingLocations(const GlslangSourceOptions &options, void AssignVaryingLocations(const GlslangSourceOptions &options,
...@@ -563,12 +554,12 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -563,12 +554,12 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
{ {
uint32_t lineRasterEmulationPositionLocation = locationsUsedForEmulation++; uint32_t lineRasterEmulationPositionLocation = locationsUsedForEmulation++;
gl::ShaderBitSet allActiveStages; for (const gl::ShaderType shaderType : programState.getLinkedShaderStages())
allActiveStages.set(); {
AddLocationInfo(variableInfoMapOut, sh::vk::kLineRasterEmulationPosition, AddLocationInfo(variableInfoMapOut, sh::vk::kLineRasterEmulationPosition,
lineRasterEmulationPositionLocation, ShaderInterfaceVariableInfo::kInvalid, lineRasterEmulationPositionLocation,
allActiveStages); ShaderInterfaceVariableInfo::kInvalid, shaderType);
}
} }
// Assign varying locations. // Assign varying locations.
...@@ -581,6 +572,15 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -581,6 +572,15 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
const gl::PackedVarying &varying = *varyingReg.packedVarying; const gl::PackedVarying &varying = *varyingReg.packedVarying;
uint32_t location = varyingReg.registerRow + locationsUsedForEmulation;
uint32_t component = ShaderInterfaceVariableInfo::kInvalid;
if (varyingReg.registerColumn > 0)
{
ASSERT(!varying.varying().isStruct());
ASSERT(!gl::IsMatrixType(varying.varying().type));
component = varyingReg.registerColumn;
}
// In the following: // In the following:
// //
// struct S { vec4 field; }; // struct S { vec4 field; };
...@@ -588,23 +588,30 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -588,23 +588,30 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
// //
// "_uvarStruct" is found through |parentStructMappedName|, with |varying->mappedName| // "_uvarStruct" is found through |parentStructMappedName|, with |varying->mappedName|
// being "_ufield". In such a case, use |parentStructMappedName|. // being "_ufield". In such a case, use |parentStructMappedName|.
const std::string &name = if (varying.frontVarying.varying)
varying.isStructField() ? varying.parentStructMappedName : varying.varying->mappedName;
uint32_t location = varyingReg.registerRow + locationsUsedForEmulation;
uint32_t component = ShaderInterfaceVariableInfo::kInvalid;
if (varyingReg.registerColumn > 0)
{ {
ASSERT(!varying.varying->isStruct()); const std::string &name = varying.isStructField()
ASSERT(!gl::IsMatrixType(varying.varying->type)); ? varying.frontVarying.parentStructMappedName
component = varyingReg.registerColumn; : varying.frontVarying.varying->mappedName;
AddLocationInfo(variableInfoMapOut, name, location, component,
varying.frontVarying.stage);
}
if (varying.backVarying.varying)
{
const std::string &name = varying.isStructField()
? varying.backVarying.parentStructMappedName
: varying.backVarying.varying->mappedName;
AddLocationInfo(variableInfoMapOut, name, location, component,
varying.backVarying.stage);
} }
AddLocationInfo(variableInfoMapOut, name, location, component, varying.shaderStages);
} }
// Add an entry for inactive varyings. // Add an entry for inactive varyings.
for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingMappedNames()) const gl::ShaderMap<std::vector<std::string>> &inactiveVaryingMappedNames =
resources.varyingPacking.getInactiveVaryingMappedNames();
for (const gl::ShaderType shaderType : programState.getLinkedShaderStages())
{
for (const std::string &varyingName : inactiveVaryingMappedNames[shaderType])
{ {
bool isBuiltin = angle::BeginsWith(varyingName, "gl_"); bool isBuiltin = angle::BeginsWith(varyingName, "gl_");
if (isBuiltin) if (isBuiltin)
...@@ -612,17 +619,17 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -612,17 +619,17 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
continue; continue;
} }
// TODO(syoussefi): inactive varying names should be unique. However, due to mishandling of // If name is already in the map, it will automatically have marked all other stages
// partially captured arrays, a varying name can end up in both the active and inactive // inactive.
// lists. The test below should be removed once that issue is resolved.
// http://anglebug.com/4140
if (variableInfoMapOut->find(varyingName) != variableInfoMapOut->end()) if (variableInfoMapOut->find(varyingName) != variableInfoMapOut->end())
{ {
continue; continue;
} }
AddLocationInfo(variableInfoMapOut, varyingName, ShaderInterfaceVariableInfo::kInvalid, // Otherwise, add an entry for it with all locations inactive.
ShaderInterfaceVariableInfo::kInvalid, gl::ShaderBitSet()); ShaderInterfaceVariableInfo *info = &(*variableInfoMapOut)[varyingName];
ASSERT(info->location[shaderType] == ShaderInterfaceVariableInfo::kInvalid);
}
} }
} }
...@@ -675,11 +682,8 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS ...@@ -675,11 +682,8 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS
ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension); ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension);
gl::ShaderBitSet vertexOnly;
vertexOnly.set(gl::ShaderType::Vertex);
AddLocationInfo(variableInfoMapOut, xfbVaryingName, xfbVaryingLocation, AddLocationInfo(variableInfoMapOut, xfbVaryingName, xfbVaryingLocation,
ShaderInterfaceVariableInfo::kInvalid, vertexOnly); ShaderInterfaceVariableInfo::kInvalid, gl::ShaderType::Vertex);
SetXfbInfo(variableInfoMapOut, xfbVaryingName, bufferIndex, currentOffset, SetXfbInfo(variableInfoMapOut, xfbVaryingName, bufferIndex, currentOffset,
currentStride); currentStride);
} }
...@@ -703,7 +707,7 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS ...@@ -703,7 +707,7 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS
const gl::PackedVarying *varying = varyingReg.packedVarying; const gl::PackedVarying *varying = varyingReg.packedVarying;
if (varying->varying->name == tfVarying.name) if (varying->frontVarying.varying->name == tfVarying.name)
{ {
originalVarying = varying; originalVarying = varying;
break; break;
...@@ -712,9 +716,10 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS ...@@ -712,9 +716,10 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramState &programS
if (originalVarying) if (originalVarying)
{ {
const std::string &mappedName = originalVarying->isStructField() const std::string &mappedName =
? originalVarying->parentStructMappedName originalVarying->isStructField()
: originalVarying->varying->mappedName; ? originalVarying->frontVarying.parentStructMappedName
: originalVarying->frontVarying.varying->mappedName;
// Set xfb info for this varying. AssignVaryingLocations should have already added // Set xfb info for this varying. AssignVaryingLocations should have already added
// location information for these varyings. // location information for these varyings.
......
...@@ -6166,9 +6166,6 @@ void main() ...@@ -6166,9 +6166,6 @@ void main()
// Test that linking varyings by location works. // Test that linking varyings by location works.
TEST_P(GLSLTest_ES31, LinkVaryingsByLocation) TEST_P(GLSLTest_ES31, LinkVaryingsByLocation)
{ {
// http://anglebug.com/4355
ANGLE_SKIP_TEST_IF(IsVulkan() || IsMetal() || IsD3D11());
constexpr char kVS[] = R"(#version 310 es constexpr char kVS[] = R"(#version 310 es
precision highp float; precision highp float;
in vec4 position; in vec4 position;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment