Commit 06c39376 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Minimize gl_PerVertex members

As ANGLE doesn't redeclare gl_PerVertex, glslang always defines it with: gl_Position gl_PointSize gl_ClipDistance gl_CullDistance The unused members here contribute to varying component limits. The last two are unlikely to be used, and the second member is rarely used as well. This change keeps it simple and strips the trailing inactive members, which for all intents and purposes accurately minimizes this struct. Bug: angleproject:5405 Change-Id: I59c22af4988a3da7b1e428913d0ea13be9031cea Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2562754 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 0f083ab0
......@@ -124,10 +124,15 @@ void VaryingPacking::reset()
mRegisterList.clear();
mPackedVaryings.clear();
for (std::vector<std::string> inactiveVaryingMappedNames : mInactiveVaryingMappedNames)
for (std::vector<std::string> &inactiveVaryingMappedNames : mInactiveVaryingMappedNames)
{
inactiveVaryingMappedNames.clear();
}
for (std::vector<std::string> &activeBuiltIns : mActiveOutputBuiltIns)
{
activeBuiltIns.clear();
}
}
void VaryingPacking::clearRegisterMap()
......@@ -364,12 +369,12 @@ void VaryingPacking::packUserVarying(const ProgramVaryingRef &ref,
VaryingInShaderRef backVarying(ref.backShaderStage, output);
mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation);
if (input)
if (input && !input->isBuiltIn())
{
(*uniqueFullNames)[ref.frontShaderStage].insert(
mPackedVaryings.back().fullName(ref.frontShaderStage));
}
if (output)
if (output && !output->isBuiltIn())
{
(*uniqueFullNames)[ref.backShaderStage].insert(
mPackedVaryings.back().fullName(ref.backShaderStage));
......@@ -454,22 +459,31 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
const bool isSeparableProgram)
{
VaryingUniqueFullNames uniqueFullNames;
mPackedVaryings.clear();
clearRegisterMap();
reset();
for (const ProgramVaryingRef &ref : mergedVaryings)
{
const sh::ShaderVariable *input = ref.frontShader;
const sh::ShaderVariable *output = ref.backShader;
const bool isActiveBuiltInInput = input && input->isBuiltIn() && input->active;
const bool isActiveBuiltInOutput = output && output->isBuiltIn() && output->active;
// Keep track of output builtins that are used by the shader, such as gl_Position,
// gl_PointSize etc.
if (isActiveBuiltInInput)
{
mActiveOutputBuiltIns[ref.frontShaderStage].push_back(input->name);
}
// 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
// not active. GLES specs are a bit vague on whether it's allowed to only pack active
// varyings, though GLES 3.1 spec section 11.1.2.1 says that "device-dependent
// optimizations" may be used to make vertex shader outputs fit.
if ((input && output && output->staticUse) ||
(input && input->isBuiltIn() && input->active) ||
(output && output->isBuiltIn() && output->active) ||
if ((input && output && output->staticUse) || isActiveBuiltInInput ||
isActiveBuiltInOutput ||
(isSeparableProgram && ((input && input->active) || (output && output->active))))
{
const sh::ShaderVariable *varying = output ? output : input;
......@@ -508,7 +522,10 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
// program, in which case the input shader may not exist in this program.
if (!input && !isSeparableProgram)
{
mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
if (!output->isBuiltIn())
{
mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
}
continue;
}
......@@ -560,11 +577,13 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
}
}
if (input && uniqueFullNames[ref.frontShaderStage].count(input->name) == 0)
if (input && !input->isBuiltIn() &&
uniqueFullNames[ref.frontShaderStage].count(input->name) == 0)
{
mInactiveVaryingMappedNames[ref.frontShaderStage].push_back(input->mappedName);
}
if (output && uniqueFullNames[ref.backShaderStage].count(output->name) == 0)
if (output && !output->isBuiltIn() &&
uniqueFullNames[ref.backShaderStage].count(output->name) == 0)
{
mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
}
......
......@@ -221,6 +221,11 @@ class VaryingPacking final : angle::NonCopyable
return mInactiveVaryingMappedNames;
}
const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltIns() const
{
return mActiveOutputBuiltIns;
}
void reset();
private:
......@@ -249,6 +254,7 @@ class VaryingPacking final : angle::NonCopyable
std::vector<PackedVaryingRegister> mRegisterList;
std::vector<PackedVarying> mPackedVaryings;
ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames;
ShaderMap<std::vector<std::string>> mActiveOutputBuiltIns;
PackMode mPackMode;
};
......
......@@ -559,6 +559,7 @@ void AssignOutputLocations(const gl::ProgramExecutable &programExecutable,
void AssignVaryingLocations(const GlslangSourceOptions &options,
const gl::ProgramExecutable &programExecutable,
const gl::ShaderType shaderType,
const gl::ShaderType frontShaderType,
GlslangProgramInterfaceInfo *programInterfaceInfo,
ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
{
......@@ -625,11 +626,7 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
programExecutable.getResources().varyingPacking.getInactiveVaryingMappedNames();
for (const std::string &varyingName : inactiveVaryingMappedNames[shaderType])
{
bool isBuiltin = angle::BeginsWith(varyingName, "gl_");
if (isBuiltin)
{
continue;
}
ASSERT(!angle::BeginsWith(varyingName, "gl_"));
// If name is already in the map, it will automatically have marked all other stages
// inactive.
......@@ -643,6 +640,33 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
ShaderInterfaceVariableInfo *info = &(*variableInfoMapOut)[shaderType][varyingName];
ASSERT(info->location == ShaderInterfaceVariableInfo::kInvalid);
}
// Add an entry for active builtins varyings. This will allow inactive builtins, such as
// gl_PointSize, gl_ClipDistance etc to be removed.
const gl::ShaderMap<std::vector<std::string>> &activeOutputBuiltIns =
programExecutable.getResources().varyingPacking.getActiveOutputBuiltIns();
for (const std::string &builtInName : activeOutputBuiltIns[shaderType])
{
ASSERT(angle::BeginsWith(builtInName, "gl_"));
ShaderInterfaceVariableInfo *info = &(*variableInfoMapOut)[shaderType][builtInName];
info->activeStages.set(shaderType);
info->varyingIsOutput = true;
}
// If an output builtin is active in the previous stage, assume it's active in the input of the
// current stage as well.
if (frontShaderType != gl::ShaderType::InvalidEnum)
{
for (const std::string &builtInName : activeOutputBuiltIns[frontShaderType])
{
ASSERT(angle::BeginsWith(builtInName, "gl_"));
ShaderInterfaceVariableInfo *info = &(*variableInfoMapOut)[shaderType][builtInName];
info->activeStages.set(shaderType);
info->varyingIsInput = true;
}
}
}
// Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated
......@@ -1086,7 +1110,6 @@ class SpirvTransformerBase : angle::NonCopyable
// Input shader variable info map:
const ShaderInterfaceVariableInfoMap &mVariableInfoMap;
ShaderInterfaceVariableInfo mBuiltinVariableInfo;
// Transformed SPIR-V:
SpirvBlob *mSpirvBlobOut;
......@@ -1099,6 +1122,7 @@ class SpirvTransformerBase : angle::NonCopyable
// Shader variable info per id, if id is a shader variable.
std::vector<const ShaderInterfaceVariableInfo *> mVariableInfoById;
ShaderInterfaceVariableInfo mBuiltinVariableInfo;
};
void SpirvTransformerBase::onTransformBegin()
......@@ -1353,7 +1377,9 @@ class SpirvTransformer final : public SpirvTransformerBase
: SpirvTransformerBase(spirvBlobIn, variableInfoMap, shaderType, spirvBlobOut),
mHasTransformFeedbackOutput(false),
mRemoveEarlyFragmentTestsOptimization(removeEarlyFragmentTestsOptimization),
mRemoveDebugInfo(removeDebugInfo)
mRemoveDebugInfo(removeDebugInfo),
mOutputPerVertex{},
mInputPerVertex{}
{}
bool transform();
......@@ -1367,6 +1393,7 @@ class SpirvTransformer final : public SpirvTransformerBase
// Instructions that are purely informational:
void visitName(const uint32_t *instruction);
void visitMemberName(const uint32_t *instruction);
void visitTypeHelper(const uint32_t *instruction, size_t idIndex, size_t typeIdIndex);
void visitTypeArray(const uint32_t *instruction);
void visitTypePointer(const uint32_t *instruction);
......@@ -1376,10 +1403,13 @@ class SpirvTransformer final : public SpirvTransformerBase
// transformed. If false is returned, the instruction should be copied as-is.
bool transformAccessChain(const uint32_t *instruction, size_t wordCount);
bool transformCapability(const uint32_t *instruction, size_t wordCount);
bool transformDebugInfo(const uint32_t *instruction, size_t wordCount);
bool transformEmitVertex(const uint32_t *instruction, size_t wordCount);
bool transformEntryPoint(const uint32_t *instruction, size_t wordCount);
bool transformDecorate(const uint32_t *instruction, size_t wordCount);
bool transformMemberDecorate(const uint32_t *instruction, size_t wordCount);
bool transformTypePointer(const uint32_t *instruction, size_t wordCount);
bool transformTypeStruct(const uint32_t *instruction, size_t wordCount);
bool transformReturn(const uint32_t *instruction, size_t wordCount);
bool transformVariable(const uint32_t *instruction, size_t wordCount);
bool transformExecutionMode(const uint32_t *instruction, size_t wordCount);
......@@ -1418,6 +1448,18 @@ class SpirvTransformer final : public SpirvTransformerBase
std::vector<TransformedIDs> mTypePointerTransformedId;
std::vector<uint32_t> mFixedVaryingId;
std::vector<uint32_t> mFixedVaryingTypeId;
// gl_PerVertex is unique in that it's the only builtin of struct type. This struct is pruned
// by removing trailing inactive members. We therefore need to keep track of what's its type id
// as well as which is the last active member. Note that intermediate stages, i.e. geometry and
// tessellation have two gl_PerVertex declarations, one for input and one for output.
struct PerVertexData
{
uint32_t typeId;
uint32_t maxActiveMember;
};
PerVertexData mOutputPerVertex;
PerVertexData mInputPerVertex;
};
bool SpirvTransformer::transform()
......@@ -1471,6 +1513,9 @@ void SpirvTransformer::resolveVariableIds()
case spv::OpName:
visitName(instruction);
break;
case spv::OpMemberName:
visitMemberName(instruction);
break;
case spv::OpTypeArray:
visitTypeArray(instruction);
break;
......@@ -1566,11 +1611,7 @@ void SpirvTransformer::transformInstruction()
case spv::OpLine:
case spv::OpNoLine:
case spv::OpModuleProcessed:
if (mRemoveDebugInfo)
{
// Strip debug info to reduce binary size.
transformed = true;
}
transformed = transformDebugInfo(instruction, wordCount);
break;
case spv::OpCapability:
transformed = transformCapability(instruction, wordCount);
......@@ -1581,9 +1622,15 @@ void SpirvTransformer::transformInstruction()
case spv::OpDecorate:
transformed = transformDecorate(instruction, wordCount);
break;
case spv::OpMemberDecorate:
transformed = transformMemberDecorate(instruction, wordCount);
break;
case spv::OpTypePointer:
transformed = transformTypePointer(instruction, wordCount);
break;
case spv::OpTypeStruct:
transformed = transformTypeStruct(instruction, wordCount);
break;
case spv::OpVariable:
transformed = transformVariable(instruction, wordCount);
break;
......@@ -1612,7 +1659,7 @@ void SpirvTransformer::writeInputPreamble()
{
const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
if (info && info->useRelaxedPrecision && info->activeStages[mShaderType] &&
!info->varyingIsOutput)
info->varyingIsInput)
{
// This is an input varying, need to cast the mediump value that came from
// the previous stage into a highp value that the code wants to work with.
......@@ -1655,6 +1702,7 @@ void SpirvTransformer::writeOutputPrologue()
}
}
}
void SpirvTransformer::visitName(const uint32_t *instruction)
{
// We currently don't have any big-endian devices in the list of supported platforms. Literal
......@@ -1676,6 +1724,63 @@ void SpirvTransformer::visitName(const uint32_t *instruction)
mNamesById[id] = name;
}
void SpirvTransformer::visitMemberName(const uint32_t *instruction)
{
ASSERT(IsLittleEndian());
// SPIR-V 1.0 Section 3.32 Instructions, OpMemberName
constexpr size_t kIdIndex = 1;
constexpr size_t kMemberIndex = 2;
constexpr size_t kNameIndex = 3;
const uint32_t id = instruction[kIdIndex];
const uint32_t member = instruction[kMemberIndex];
const char *name = reinterpret_cast<const char *>(&instruction[kNameIndex]);
// The names and ids are unique
ASSERT(id < mNamesById.size());
ASSERT(mNamesById[id] != nullptr);
if (strcmp(mNamesById[id], "gl_PerVertex") != 0)
{
return;
}
auto infoIter = mVariableInfoMap.find(name);
// Assume output gl_PerVertex is encountered first. When the storage class of these types are
// determined, the variables can be swapped if this assumption was incorrect.
if (mOutputPerVertex.typeId == 0 || id == mOutputPerVertex.typeId)
{
mOutputPerVertex.typeId = id;
// Keep track of the range of members that are active.
const bool isActive =
infoIter != mVariableInfoMap.end() && infoIter->second.varyingIsOutput;
if (isActive && member > mOutputPerVertex.maxActiveMember)
{
mOutputPerVertex.maxActiveMember = member;
}
}
else if (mInputPerVertex.typeId == 0 || id == mInputPerVertex.typeId)
{
mInputPerVertex.typeId = id;
// Keep track of the range of members that are active.
const bool isActive = infoIter != mVariableInfoMap.end() && infoIter->second.varyingIsInput;
if (isActive && member > mInputPerVertex.maxActiveMember)
{
mInputPerVertex.maxActiveMember = member;
}
}
else
{
UNREACHABLE();
}
}
void SpirvTransformer::visitTypeHelper(const uint32_t *instruction,
const size_t idIndex,
const size_t typeIdIndex)
......@@ -1709,10 +1814,26 @@ void SpirvTransformer::visitTypeArray(const uint32_t *instruction)
void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer
constexpr size_t kIdIndex = 1;
constexpr size_t kTypeIdIndex = 3;
constexpr size_t kIdIndex = 1;
constexpr size_t kStorageClassIndex = 2;
constexpr size_t kTypeIdIndex = 3;
visitTypeHelper(instruction, kIdIndex, kTypeIdIndex);
const uint32_t typeId = instruction[kTypeIdIndex];
const uint32_t storageClass = instruction[kStorageClassIndex];
// Verify that the ids associated with input and output gl_PerVertex are correct.
if (typeId == mOutputPerVertex.typeId || typeId == mInputPerVertex.typeId)
{
// If assumption about the first gl_PerVertex encountered being Output is wrong, swap the
// two ids.
if ((typeId == mOutputPerVertex.typeId && storageClass == spv::StorageClassInput) ||
(typeId == mInputPerVertex.typeId && storageClass == spv::StorageClassOutput))
{
std::swap(mOutputPerVertex.typeId, mInputPerVertex.typeId);
}
}
}
void SpirvTransformer::visitVariable(const uint32_t *instruction)
......@@ -1925,6 +2046,29 @@ bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wor
return true;
}
bool SpirvTransformer::transformMemberDecorate(const uint32_t *instruction, size_t wordCount)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpMemberDecorate
constexpr size_t kTypeIdIndex = 1;
constexpr size_t kMemberIndex = 2;
constexpr size_t kDecorationIndex = 3;
uint32_t typeId = instruction[kTypeIdIndex];
uint32_t member = instruction[kMemberIndex];
uint32_t decoration = instruction[kDecorationIndex];
// Transform only OpMemberDecorate %gl_PerVertex N BuiltIn B
if ((typeId != mOutputPerVertex.typeId && typeId != mInputPerVertex.typeId) ||
decoration != spv::DecorationBuiltIn)
{
return false;
}
// Drop stripped fields.
return typeId == mOutputPerVertex.typeId ? member > mOutputPerVertex.maxActiveMember
: member > mInputPerVertex.maxActiveMember;
}
bool SpirvTransformer::transformCapability(const uint32_t *instruction, size_t wordCount)
{
if (!mHasTransformFeedbackOutput)
......@@ -1967,6 +2111,32 @@ bool SpirvTransformer::transformCapability(const uint32_t *instruction, size_t w
return true;
}
bool SpirvTransformer::transformDebugInfo(const uint32_t *instruction, size_t wordCount)
{
if (mRemoveDebugInfo)
{
// Strip debug info to reduce binary size.
return true;
}
// In the case of OpMemberName, unconditionally remove stripped gl_PerVertex members.
if (GetSpirvInstructionOp(instruction) == spv::OpMemberName)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpMemberName
constexpr size_t kIdIndex = 1;
constexpr size_t kMemberIndex = 2;
const uint32_t id = instruction[kIdIndex];
const uint32_t member = instruction[kMemberIndex];
// Remove the instruction if it's a stripped member of gl_PerVertex.
return (id == mOutputPerVertex.typeId && member > mOutputPerVertex.maxActiveMember) ||
(id == mInputPerVertex.typeId && member > mInputPerVertex.maxActiveMember);
}
return false;
}
bool SpirvTransformer::transformEmitVertex(const uint32_t *instruction, size_t wordCount)
{
// This is only possible in geometry shaders.
......@@ -2106,6 +2276,33 @@ bool SpirvTransformer::transformTypePointer(const uint32_t *instruction, size_t
return false;
}
bool SpirvTransformer::transformTypeStruct(const uint32_t *instruction, size_t wordCount)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpTypeStruct
constexpr size_t kIdIndex = 1;
constexpr size_t kTypeStructInstructionBaseLength = 2;
const uint32_t id = instruction[kIdIndex];
if (id != mOutputPerVertex.typeId && id != mInputPerVertex.typeId)
{
return false;
}
const uint32_t maxMembers = id == mOutputPerVertex.typeId ? mOutputPerVertex.maxActiveMember
: mInputPerVertex.maxActiveMember;
// Change the definition of the gl_PerVertex struct by stripping unused fields at the end.
const uint32_t memberCount = maxMembers + 1;
const size_t newLength = kTypeStructInstructionBaseLength + memberCount;
ASSERT(wordCount >= newLength);
const size_t instructionOffset = copyInstruction(instruction, newLength);
SetSpirvInstructionLength(&(*mSpirvBlobOut)[instructionOffset], newLength);
return true;
}
bool SpirvTransformer::transformReturn(const uint32_t *instruction, size_t wordCount)
{
if (mOpFunctionId != mEntryPointId)
......@@ -3385,6 +3582,7 @@ void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &opt
void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramExecutable &programExecutable,
const gl::ShaderType shaderType,
const gl::ShaderType frontShaderType,
GlslangProgramInterfaceInfo *programInterfaceInfo,
ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
{
......@@ -3407,8 +3605,8 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Compute))
{
// Assign varying locations.
AssignVaryingLocations(options, programExecutable, shaderType, programInterfaceInfo,
variableInfoMapOut);
AssignVaryingLocations(options, programExecutable, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
options.supportsTransformFeedbackExtension && (shaderType == gl::ShaderType::Vertex))
......@@ -3470,10 +3668,14 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
}
}
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
for (const gl::ShaderType shaderType : programState.getExecutable().getLinkedShaderStages())
{
GlslangAssignLocations(options, programState.getExecutable(), shaderType,
GlslangAssignLocations(options, programState.getExecutable(), shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
frontShaderType = shaderType;
}
}
......
......@@ -86,7 +86,9 @@ struct ShaderInterfaceVariableInfo
// mismatch between the shaders. For example, either the VS casts highp->mediump
// or the FS casts mediump->highp.
bool useRelaxedPrecision = false;
// Indicate if varying is input or output
// Indicate if varying is input or output, or both (in case of for example gl_Position in a
// geometry shader)
bool varyingIsInput = false;
bool varyingIsOutput = false;
// For vertex attributes, this is the number of components / locations. These are used by the
// vertex attribute aliasing transformation only.
......@@ -120,6 +122,7 @@ void GlslangGenTransformFeedbackEmulationOutputs(
void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramExecutable &programExecutable,
const gl::ShaderType shaderType,
const gl::ShaderType frontShaderType,
GlslangProgramInterfaceInfo *programInterfaceInfo,
gl::ShaderMap<ShaderInterfaceVariableInfoMap> *variableInfoMapOut);
......
......@@ -432,7 +432,8 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
&xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
GlslangAssignLocations(options, programState.getExecutable(), gl::ShaderType::Vertex,
&xfbOnlyInterfaceInfo, &xfbOnlyVariableMaps);
gl::ShaderType::InvalidEnum, &xfbOnlyInterfaceInfo,
&xfbOnlyVariableMaps);
*xfbOnlyVSVariableInfoMapOut = std::move(xfbOnlyVariableMaps[gl::ShaderType::Vertex]);
}
}
......
......@@ -227,6 +227,7 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *
info->xfbOffset = stream->readInt<uint32_t>();
info->xfbStride = stream->readInt<uint32_t>();
info->useRelaxedPrecision = stream->readBool();
info->varyingIsInput = stream->readBool();
info->varyingIsOutput = stream->readBool();
info->attributeComponentCount = stream->readInt<uint8_t>();
info->attributeLocationCount = stream->readInt<uint8_t>();
......@@ -254,6 +255,7 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
stream->writeInt(it.second.xfbOffset);
stream->writeInt(it.second.xfbStride);
stream->writeBool(it.second.useRelaxedPrecision);
stream->writeBool(it.second.varyingIsInput);
stream->writeBool(it.second.varyingIsOutput);
stream->writeInt(it.second.attributeComponentCount);
stream->writeInt(it.second.attributeLocationCount);
......@@ -923,7 +925,7 @@ void ProgramExecutableVk::resolvePrecisionMismatch(const gl::ProgramMergedVaryin
// The output is lower precision than the input, adjust the input
info = &mVariableInfoMap[mergedVarying.backShaderStage]
[mergedVarying.backShader->mappedName];
info->varyingIsOutput = false;
info->varyingIsInput = true;
info->useRelaxedPrecision = true;
}
}
......
......@@ -67,6 +67,7 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
// Now that the program pipeline has all of the programs attached, the various descriptor
// set/binding locations need to be re-assigned to their correct values.
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
for (const gl::ShaderType shaderType : glPipeline->getExecutable().getLinkedShaderStages())
{
gl::Program *glProgram =
......@@ -82,8 +83,9 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
programProgramInterfaceInfo.locationsUsedForXfbExtension;
GlslangAssignLocations(options, glProgram->getState().getExecutable(), shaderType,
&glslangProgramInterfaceInfo,
frontShaderType, &glslangProgramInterfaceInfo,
&mExecutable.getShaderInterfaceVariableInfoMap());
frontShaderType = shaderType;
}
}
......
......@@ -189,8 +189,6 @@
// Geometry shader support:
3580 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.types.float_struct = SKIP
5404 VULKAN : dEQP-GLES31.functional.geometry_shading.query.primitives_generated* = SKIP
5405 VULKAN : dEQP-GLES31.functional.geometry_shading.basic.output_* = FAIL
5405 VULKAN : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_vary_by_* = FAIL
5406 VULKAN : dEQP-GLES31.functional.geometry_shading.input.*adjacency* = SKIP
5407 VULKAN : dEQP-GLES31.functional.geometry_shading.layered.* = SKIP
5407 VULKAN : dEQP-GLES31.functional.geometry_shading.instanced.invocation_per_layer* = SKIP
......
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