Commit d654ac9b by Jamie Madill Committed by Commit Bot

Program: Support multiple varying packings.

Instead of using a single varying packing for all program stages, we switch to using a varying register packing for each pair of input/output shaders. This allows several valid use cases that use many varying to succeed. For instance Geometry Shaders have both an input and output varying packing. With tessellation shaders the upper bound of valid varying packings in one Program goes up even more. We keep multiple varying packings at once inside a new "ProgramVaryingPacking" class. Internally the class keeps a unique varying mapping for each input/output interface in the program. Separable programs with "open" interfaces are handled specially. Fixes a bug where varying counting was artificially limited for programs with more than two shaders. This CL also disables GS support when we're emulating line raster so we don't have to figure out the details on how to place the special position varying. Bug: angleproject:5496 Change-Id: I1f9a327c4750caef570c608d86953e9d0cc5eea3 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2606532 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 8943d1e2
......@@ -368,7 +368,6 @@ class ProgramState final : angle::NonCopyable
friend class MemoryProgramCache;
friend class Program;
void updateTransformFeedbackStrides();
void updateActiveSamplers();
void updateProgramInterfaceInputs();
void updateProgramInterfaceOutputs();
......@@ -490,10 +489,6 @@ class Program final : public LabeledObject, public angle::Subject, public HasAtt
void bindFragmentOutputLocation(GLuint index, const char *name);
void bindFragmentOutputIndex(GLuint index, const char *name);
bool linkMergedVaryings(const Context *context,
const ProgramMergedVaryings &mergedVaryings,
VaryingPacking *varyingPacking);
// KHR_parallel_shader_compile
// Try to link the program asynchrously. As a result, background threads may be launched to
// execute the linking tasks concurrently.
......@@ -868,14 +863,6 @@ class Program final : public LabeledObject, public angle::Subject, public HasAtt
void updateLinkedShaderStages();
bool linkValidateTransformFeedback(const Version &version,
InfoLog &infoLog,
const ProgramMergedVaryings &linkedVaryings,
ShaderType stage,
const Caps &caps) const;
void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings, ShaderType stage);
int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const;
bool isOutputSecondaryForLink(const sh::ShaderVariable &outputVariable) const;
bool linkOutputVariables(const Caps &caps,
......
......@@ -334,6 +334,26 @@ class ProgramExecutable final : public angle::Subject
void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,
std::vector<SamplerBinding> &samplerBindings);
bool linkMergedVaryings(const Context *context,
const HasAttachedShaders &programOrPipeline,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &transformFeedbackVaryingNames,
bool isSeparable,
ProgramVaryingPacking *varyingPacking);
bool linkValidateTransformFeedback(
const Context *context,
const ProgramMergedVaryings &varyings,
ShaderType stage,
const std::vector<std::string> &transformFeedbackVaryingNames);
void gatherTransformFeedbackVaryings(
const ProgramMergedVaryings &varyings,
ShaderType stage,
const std::vector<std::string> &transformFeedbackVaryingNames);
void updateTransformFeedbackStrides();
InfoLog mInfoLog;
ShaderBitSet mLinkedGraphicsShaderStages;
......
......@@ -221,7 +221,7 @@ struct ProgramLinkedResources
std::vector<BufferVariable> *bufferVariablesOut,
std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
VaryingPacking varyingPacking;
ProgramVaryingPacking varyingPacking;
UniformBlockLinker uniformBlockLinker;
ShaderStorageBlockLinker shaderStorageBlockLinker;
AtomicCounterBufferLinker atomicCounterBufferLinker;
......
......@@ -420,7 +420,7 @@ angle::Result ProgramPipeline::link(const Context *context)
}
ProgramMergedVaryings mergedVaryings;
VaryingPacking varyingPacking;
ProgramVaryingPacking varyingPacking;
if (!getExecutable().isCompute())
{
......@@ -438,14 +438,22 @@ angle::Result ProgramPipeline::link(const Context *context)
}
mergedVaryings = GetMergedVaryingsFromShaders(*this);
for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
// If separable program objects are in use, the set of attributes captured is taken
// from the program object active on the last vertex processing stage.
Program *tfProgram = mState.mPrograms[ShaderType::Geometry];
if (!tfProgram)
{
Program *program = mState.mPrograms[shaderType];
ASSERT(program);
if (!program->linkMergedVaryings(context, mergedVaryings, &varyingPacking))
{
return angle::Result::Stop;
}
tfProgram = mState.mPrograms[ShaderType::Vertex];
}
const std::vector<std::string> &transformFeedbackVaryingNames =
tfProgram->getState().getTransformFeedbackVaryingNames();
if (!mState.mExecutable->linkMergedVaryings(context, *this, mergedVaryings,
transformFeedbackVaryingNames, false,
&varyingPacking))
{
return angle::Result::Stop;
}
}
......
......@@ -109,6 +109,32 @@ bool InterfaceVariablesMatch(const sh::ShaderVariable &front, const sh::ShaderVa
const std::string &frontName = front.isShaderIOBlock ? front.structName : front.name;
return backName == frontName;
}
GLint GetMaxShaderInputVectors(const Caps &caps, ShaderType shaderStage)
{
switch (shaderStage)
{
case ShaderType::Geometry:
return caps.maxGeometryInputComponents / 4;
case ShaderType::Fragment:
return caps.maxFragmentInputComponents / 4;
default:
return std::numeric_limits<GLint>::max();
}
}
GLint GetMaxShaderOutputVectors(const Caps &caps, ShaderType shaderStage)
{
switch (shaderStage)
{
case ShaderType::Vertex:
return caps.maxVertexOutputComponents / 4;
case ShaderType::Geometry:
return caps.maxGeometryOutputComponents / 4;
default:
return std::numeric_limits<GLint>::max();
}
}
} // anonymous namespace
// Implementation of VaryingInShaderRef
......@@ -719,6 +745,8 @@ void VaryingPacking::collectTFVarying(const std::string &tfVarying,
bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
GLint maxVaryingVectors,
PackMode packMode,
ShaderType frontShaderStage,
ShaderType backShaderStage,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings,
const bool isSeparableProgram)
......@@ -732,6 +760,12 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
const sh::ShaderVariable *input = ref.frontShader;
const sh::ShaderVariable *output = ref.backShader;
if ((input && ref.frontShaderStage != frontShaderStage) ||
(output && ref.backShaderStage != backShaderStage))
{
continue;
}
const bool isActiveBuiltInInput = input && input->isBuiltIn() && input->active;
const bool isActiveBuiltInOutput = output && output->isBuiltIn() && output->active;
......@@ -834,6 +868,111 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
return true;
}
// ProgramVaryingPacking implementation.
ProgramVaryingPacking::ProgramVaryingPacking() = default;
ProgramVaryingPacking::~ProgramVaryingPacking() = default;
const VaryingPacking &ProgramVaryingPacking::getInputPacking(ShaderType backShaderStage) const
{
ShaderType frontShaderStage = mBackToFrontStageMap[backShaderStage];
// If there's a missing shader stage, return the compute shader packing which is always empty.
if (frontShaderStage == ShaderType::InvalidEnum)
{
ASSERT(mVaryingPackings[ShaderType::Compute].getMaxSemanticIndex() == 0);
return mVaryingPackings[ShaderType::Compute];
}
return mVaryingPackings[frontShaderStage];
}
const VaryingPacking &ProgramVaryingPacking::getOutputPacking(ShaderType frontShaderStage) const
{
return mVaryingPackings[frontShaderStage];
}
bool ProgramVaryingPacking::collectAndPackUserVaryings(InfoLog &infoLog,
const Caps &caps,
PackMode packMode,
const ShaderBitSet &attachedShadersMask,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings,
bool isSeparableProgram)
{
mBackToFrontStageMap.fill(ShaderType::InvalidEnum);
ShaderBitSet attachedShaders = attachedShadersMask;
ShaderType frontShaderStage = attachedShaders.first();
attachedShaders[frontShaderStage] = false;
// Special case for start-after-vertex.
if (frontShaderStage != ShaderType::Vertex)
{
ASSERT(isSeparableProgram);
ShaderType emulatedFrontShaderStage = ShaderType::Vertex;
ShaderType backShaderStage = frontShaderStage;
if (!mVaryingPackings[emulatedFrontShaderStage].collectAndPackUserVaryings(
infoLog, GetMaxShaderInputVectors(caps, backShaderStage), packMode,
ShaderType::InvalidEnum, backShaderStage, mergedVaryings, tfVaryings,
isSeparableProgram))
{
return false;
}
mBackToFrontStageMap[backShaderStage] = emulatedFrontShaderStage;
}
// Process input/output shader pairs.
for (ShaderType backShaderStage : attachedShaders)
{
GLint maxVaryingVectors;
if (frontShaderStage == ShaderType::Vertex && backShaderStage == ShaderType::Fragment)
{
maxVaryingVectors = caps.maxVaryingVectors;
}
else
{
GLint outputVaryingsMax = GetMaxShaderOutputVectors(caps, frontShaderStage);
GLint inputVaryingsMax = GetMaxShaderInputVectors(caps, backShaderStage);
maxVaryingVectors = std::min(inputVaryingsMax, outputVaryingsMax);
}
ASSERT(maxVaryingVectors > 0 && maxVaryingVectors < std::numeric_limits<GLint>::max());
if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
infoLog, maxVaryingVectors, packMode, frontShaderStage, backShaderStage,
mergedVaryings, tfVaryings, isSeparableProgram))
{
return false;
}
mBackToFrontStageMap[backShaderStage] = frontShaderStage;
frontShaderStage = backShaderStage;
}
// Special case for stop-before-fragment.
if (frontShaderStage != ShaderType::Fragment)
{
ASSERT(isSeparableProgram);
if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
infoLog, GetMaxShaderOutputVectors(caps, frontShaderStage), packMode,
frontShaderStage, ShaderType::InvalidEnum, mergedVaryings, tfVaryings,
isSeparableProgram))
{
return false;
}
ShaderType emulatedBackShaderStage = ShaderType::Fragment;
mBackToFrontStageMap[emulatedBackShaderStage] = frontShaderStage;
}
return true;
}
ProgramMergedVaryings GetMergedVaryingsFromShaders(const HasAttachedShaders &programOrPipeline)
{
Shader *frontShader = nullptr;
......
......@@ -24,6 +24,7 @@ namespace gl
{
class HasAttachedShaders;
class InfoLog;
struct Caps;
struct ProgramVaryingRef;
using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
......@@ -206,12 +207,14 @@ class VaryingPacking final : angle::NonCopyable
VaryingPacking();
~VaryingPacking();
bool collectAndPackUserVaryings(InfoLog &infoLog,
GLint maxVaryingVectors,
PackMode packMode,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings,
const bool isSeparableProgram);
ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog,
GLint maxVaryingVectors,
PackMode packMode,
ShaderType frontShaderStage,
ShaderType backShaderStage,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings,
const bool isSeparableProgram);
struct Register
{
......@@ -237,7 +240,7 @@ class VaryingPacking final : angle::NonCopyable
return mInactiveVaryingMappedNames;
}
const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltIns() const
const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltInNames() const
{
return mActiveOutputBuiltIns;
}
......@@ -288,6 +291,31 @@ class VaryingPacking final : angle::NonCopyable
ShaderMap<std::vector<std::string>> mActiveOutputBuiltIns;
};
class ProgramVaryingPacking final : angle::NonCopyable
{
public:
ProgramVaryingPacking();
~ProgramVaryingPacking();
const VaryingPacking &getInputPacking(ShaderType backShaderStage) const;
const VaryingPacking &getOutputPacking(ShaderType frontShaderStage) const;
ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog,
const Caps &caps,
PackMode packMode,
const ShaderBitSet &attachedShadersMask,
const ProgramMergedVaryings &mergedVaryings,
const std::vector<std::string> &tfVaryings,
bool isSeparableProgram);
private:
// Indexed by the front shader.
ShaderMap<VaryingPacking> mVaryingPackings;
// Looks up the front stage from the back stage.
ShaderMap<ShaderType> mBackToFrontStageMap;
};
// Takes an abstract handle to a program or pipeline.
ProgramMergedVaryings GetMergedVaryingsFromShaders(const HasAttachedShaders &programOrPipeline);
} // namespace gl
......
......@@ -46,7 +46,8 @@ class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
VaryingPacking varyingPacking;
return varyingPacking.collectAndPackUserVaryings(
infoLog, maxVaryings, packMode, mergedVaryings, transformFeedbackVaryings, false);
infoLog, maxVaryings, packMode, ShaderType::Vertex, ShaderType::Fragment,
mergedVaryings, transformFeedbackVaryings, false);
}
// Uses the "relaxed" ANGLE packing mode.
......
......@@ -13,7 +13,7 @@ namespace rx
angle::Result ProgramPipelineImpl::link(const gl::Context *context,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::VaryingPacking &varyingPacking)
const gl::ProgramVaryingPacking &varyingPacking)
{
return angle::Result::Continue;
}
......
......@@ -25,7 +25,7 @@ class ProgramPipelineImpl : public angle::NonCopyable
virtual angle::Result link(const gl::Context *context,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::VaryingPacking &varyingPacking);
const gl::ProgramVaryingPacking &varyingPacking);
const gl::ProgramPipelineState &getState() const { return mState; }
......
......@@ -2112,11 +2112,14 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
}
}
const gl::VaryingPacking &varyingPacking =
resources.varyingPacking.getOutputPacking(gl::ShaderType::Vertex);
ProgramD3DMetadata metadata(mRenderer, shadersD3D, context->getClientType());
BuiltinVaryingsD3D builtins(metadata, resources.varyingPacking);
BuiltinVaryingsD3D builtins(metadata, varyingPacking);
mDynamicHLSL->generateShaderLinkHLSL(context->getCaps(), mState, metadata,
resources.varyingPacking, builtins, &mShaderHLSL);
mDynamicHLSL->generateShaderLinkHLSL(context->getCaps(), mState, metadata, varyingPacking,
builtins, &mShaderHLSL);
const ShaderD3D *vertexShader = shadersD3D[gl::ShaderType::Vertex];
mUsesPointSize = vertexShader && vertexShader->usesPointSize();
......@@ -2132,7 +2135,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
if (mRenderer->getMajorShaderModel() >= 4)
{
mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(
resources.varyingPacking, builtins, mHasANGLEMultiviewEnabled,
varyingPacking, builtins, mHasANGLEMultiviewEnabled,
metadata.canSelectViewInVertexShader());
}
......@@ -2140,7 +2143,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
defineUniformsAndAssignRegisters();
gatherTransformFeedbackVaryings(resources.varyingPacking, builtins[gl::ShaderType::Vertex]);
gatherTransformFeedbackVaryings(varyingPacking, builtins[gl::ShaderType::Vertex]);
linkResources(resources);
......
......@@ -476,7 +476,7 @@ bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg, bool
// Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated
// values for the SPIR-V transformation.
void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
const gl::VaryingPacking &varyingPacking,
std::string *xfbShaderSource,
uint32_t *locationsUsedForXfbExtensionOut)
{
......@@ -500,8 +500,8 @@ void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programSt
// clip space and prerotation), so it cannot be captured directly.
//
// The rest of the builtins are captured by decorating gl_PerVertex directly.
uint32_t xfbVaryingLocation = resources.varyingPacking.getMaxSemanticIndex() +
++(*locationsUsedForXfbExtensionOut);
uint32_t xfbVaryingLocation =
varyingPacking.getMaxSemanticIndex() + ++(*locationsUsedForXfbExtensionOut);
std::string xfbVaryingName = kXfbBuiltInPrefix + tfVaryingName;
......@@ -664,7 +664,7 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
// 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 =
varyingPacking.getActiveOutputBuiltIns();
varyingPacking.getActiveOutputBuiltInNames();
for (const std::string &builtInName : activeOutputBuiltIns[shaderType])
{
ASSERT(gl::IsBuiltInName(builtInName));
......@@ -690,7 +690,7 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
}
// Add an entry for gl_PerVertex, for use with transform feedback capture of built-ins.
ShaderInterfaceVariableInfo &info = variableInfoMapOut->add(shaderType, "gl_PerVertex");
ShaderInterfaceVariableInfo &info = variableInfoMapOut->addOrGet(shaderType, "gl_PerVertex");
info.activeStages.set(shaderType);
}
......@@ -3813,7 +3813,7 @@ void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &opt
void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramExecutable &programExecutable,
const gl::VaryingPacking &varyingPacking,
const gl::ProgramVaryingPacking &varyingPacking,
const gl::ShaderType shaderType,
const gl::ShaderType frontShaderType,
GlslangProgramInterfaceInfo *programInterfaceInfo,
......@@ -3835,16 +3835,27 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Compute))
{
const gl::VaryingPacking &inputPacking = varyingPacking.getInputPacking(shaderType);
const gl::VaryingPacking &outputPacking = varyingPacking.getOutputPacking(shaderType);
// Assign varying locations.
AssignVaryingLocations(options, varyingPacking, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
if (shaderType != gl::ShaderType::Vertex)
{
AssignVaryingLocations(options, inputPacking, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
}
if (shaderType != gl::ShaderType::Fragment)
{
AssignVaryingLocations(options, outputPacking, shaderType, frontShaderType,
programInterfaceInfo, variableInfoMapOut);
}
if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
options.supportsTransformFeedbackExtension &&
(shaderType == programExecutable.getLinkedTransformFeedbackStage()))
{
AssignTransformFeedbackExtensionQualifiers(
programExecutable, varyingPacking,
programExecutable, outputPacking,
programInterfaceInfo->locationsUsedForXfbExtension, shaderType, variableInfoMapOut);
}
}
......@@ -3881,7 +3892,7 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
if (options.supportsTransformFeedbackExtension)
{
GenerateTransformFeedbackExtensionOutputs(
programState, resources, xfbSource,
programState, resources.varyingPacking.getOutputPacking(xfbStage), xfbSource,
&programInterfaceInfo->locationsUsedForXfbExtension);
}
else if (options.emulateTransformFeedback)
......
......@@ -173,7 +173,7 @@ void GlslangGenTransformFeedbackEmulationOutputs(
void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramExecutable &programExecutable,
const gl::VaryingPacking &varyingPacking,
const gl::ProgramVaryingPacking &varyingPacking,
const gl::ShaderType shaderType,
const gl::ShaderType frontShaderType,
GlslangProgramInterfaceInfo *programInterfaceInfo,
......
......@@ -54,7 +54,7 @@ void ProgramPipelineVk::fillProgramStateMap(
angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::VaryingPacking &varyingPacking)
const gl::ProgramVaryingPacking &varyingPacking)
{
ContextVk *contextVk = vk::GetImpl(glContext);
const gl::State &glState = glContext->getState();
......@@ -78,7 +78,7 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
// The program interface info must survive across shaders, except
// for some program-specific values.
ProgramVk *programVk = vk::GetImpl(glProgram);
GlslangProgramInterfaceInfo &programProgramInterfaceInfo =
const GlslangProgramInterfaceInfo &programProgramInterfaceInfo =
programVk->getGlslangProgramInterfaceInfo();
glslangProgramInterfaceInfo.locationsUsedForXfbExtension =
programProgramInterfaceInfo.locationsUsedForXfbExtension;
......
......@@ -47,7 +47,7 @@ class ProgramPipelineVk : public ProgramPipelineImpl
angle::Result link(const gl::Context *glContext,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::VaryingPacking &varyingPacking) override;
const gl::ProgramVaryingPacking &varyingPacking) override;
angle::Result updateUniforms(ContextVk *contextVk);
......
......@@ -165,7 +165,7 @@ class ProgramVk : public ProgramImpl
variableInfoMap);
}
GlslangProgramInterfaceInfo &getGlslangProgramInterfaceInfo()
const GlslangProgramInterfaceInfo &getGlslangProgramInterfaceInfo()
{
return mGlslangProgramInterfaceInfo;
}
......
......@@ -915,12 +915,13 @@ void RendererVk::ensureCapsInitialized() const
vk::HasShaderImageAtomicsSupport(this, mNativeExtensions) ||
getFeatures().exposeNonConformantExtensionsAndVersions.enabled;
// Geometry shader is optional.
if (mPhysicalDeviceFeatures.geometryShader)
// Geometry shaders are required for ES 3.2.
// We can't support GS when we are emulating line raster due to the tricky position varying.
if (mPhysicalDeviceFeatures.geometryShader && !mFeatures.basicGLLineRasterization.enabled)
{
// TODO: geometry shader support is incomplete. http://anglebug.com/3571
mNativeExtensions.geometryShader =
getFeatures().exposeNonConformantExtensionsAndVersions.enabled;
mFeatures.exposeNonConformantExtensionsAndVersions.enabled;
mNativeCaps.maxFramebufferLayers = LimitToInt(limitsVk.maxFramebufferLayers);
mNativeCaps.layerProvokingVertex = GL_LAST_VERTEX_CONVENTION_EXT;
......
......@@ -1632,6 +1632,144 @@ void main()
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Tests that varying limits work as expected with geometry shaders.
TEST_P(GeometryShaderTest, MaxVaryings)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
// Get appropriate limitations.
GLint maxVertexOutputComponents = 0;
glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
ASSERT_GT(maxVertexOutputComponents, 0);
GLint maxGeometryInputComponents = 0;
glGetIntegerv(GL_MAX_GEOMETRY_INPUT_COMPONENTS, &maxGeometryInputComponents);
ASSERT_GT(maxGeometryInputComponents, 0);
GLint maxGeometryOutputComponents = 0;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &maxGeometryOutputComponents);
ASSERT_GT(maxGeometryOutputComponents, 0);
GLint maxFragmentInputComponents = 0;
glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &maxFragmentInputComponents);
ASSERT_GT(maxFragmentInputComponents, 0);
GLint vertexToGeometryVaryings =
std::min(maxVertexOutputComponents, maxGeometryInputComponents) / 4;
GLint geometryToFragmentVaryings =
std::min(maxGeometryOutputComponents, maxFragmentInputComponents) / 4;
GLint varyingCount = std::min(vertexToGeometryVaryings, geometryToFragmentVaryings);
// Reserve gl_Position;
varyingCount--;
// Create a vertex shader with "varyingCount" outputs.
std::stringstream vsStream;
vsStream << R"(#version 310 es
uniform vec4 uniOne;
in vec4 position;
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
vsStream << "out vec4 v" << varyingIndex << ";\n";
}
vsStream << R"(
void main()
{
gl_Position = position;
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
vsStream << " v" << varyingIndex << " = uniOne * " << varyingIndex << ".0;\n";
}
vsStream << "}";
// Create a GS with "varyingCount" inputs and "varyingCount" outputs.
std::stringstream gsStream;
gsStream << R"(#version 310 es
#extension GL_EXT_geometry_shader : require
layout (triangles) in;
layout (triangle_strip, max_vertices = 4) out;
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
gsStream << "in vec4 v" << varyingIndex << "[];\n";
}
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
gsStream << "out vec4 o" << varyingIndex << ";\n";
}
gsStream << R"(
void main()
{
for (int n = 0; n < gl_in.length(); n++)
{
gl_Position = gl_in[n].gl_Position;
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
gsStream << " o" << varyingIndex << " = v" << varyingIndex << "[n];\n";
}
gsStream << R"(
EmitVertex();
}
EndPrimitive();
}
)";
// Create a FS with "varyingCount" inputs.
std::stringstream fsStream;
fsStream << R"(#version 310 es
precision mediump float;
out vec4 color;
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
fsStream << "in vec4 o" << varyingIndex << ";\n";
}
fsStream << R"(
void main()
{
color = vec4(0, 1, 0, 1);
)";
for (GLint varyingIndex = 0; varyingIndex < varyingCount; ++varyingIndex)
{
fsStream << " if (o" << varyingIndex << " != vec4(" << varyingIndex << ".0))\n"
<< " color = vec4(1, 0, 0, 1);\n";
}
fsStream << "}";
const std::string vs = vsStream.str();
const std::string gs = gsStream.str();
const std::string fs = fsStream.str();
ANGLE_GL_PROGRAM_WITH_GS(program, vs.c_str(), gs.c_str(), fs.c_str());
glUseProgram(program);
GLint uniLoc = glGetUniformLocation(program, "uniOne");
ASSERT_NE(-1, uniLoc);
glUniform4f(uniLoc, 1.0f, 1.0f, 1.0f, 1.0f);
drawQuad(program, "position", 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
ANGLE_INSTANTIATE_TEST_ES3(GeometryShaderTestES3);
ANGLE_INSTANTIATE_TEST_ES31_AND(GeometryShaderTest,
WithEmulatedPrerotation(ES31_VULKAN(), 90),
......
......@@ -2657,6 +2657,9 @@ TEST_P(TransformFeedbackTestES32, PrimitivesWrittenAndGenerated)
ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows());
ANGLE_SKIP_TEST_IF(IsVulkan() && IsNVIDIA() && IsWindows7());
// http://anglebug.com/5539
ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux());
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
......
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