GL: Implement clip distance state emulation

Pass the current set of enabled clip distances
to vertex shaders via an internal uniform and
dynamically set disabled elements to zero.

Bug: angleproject:7880
Change-Id: I709d31dc7ca0606decf49adf674460a941837683
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4094314
Commit-Queue: Alexey Knyazev <lexa.knyazev@gmail.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Alexey Knyazev 2022-12-09 00:00:00 +00:00 коммит произвёл Angle LUCI CQ
Родитель 8668cac1a9
Коммит 28e7adca96
20 изменённых файлов: 162 добавлений и 30 удалений

Просмотреть файл

@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 315
#define ANGLE_SH_VERSION 316
enum ShShaderSpec
{
@ -417,6 +417,9 @@ struct ShCompileOptions
// When clip and cull distances are used simultaneously, D3D11 can support up to four of each.
uint64_t limitSimultaneousClipAndCullDistanceUsage : 1;
// Use an integer uniform to pass a bitset of enabled clip distances.
uint64_t emulateClipDistanceState : 1;
ShCompileOptionsMetal metal;
ShPixelLocalStorageOptions pls;
};
@ -857,6 +860,7 @@ unsigned int GetImage2DRegisterIndex(const ShHandle handle);
// handle: Specifies the compiler
const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle);
bool HasClipDistanceInVertexShader(const ShHandle handle);
bool HasDiscardInFragmentShader(const ShHandle handle);
bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle);

Просмотреть файл

@ -467,10 +467,12 @@ struct FeaturesGL : FeatureSetBase
"packUnorm4x8 fails on Pixel 4 if it is not passed a highp vec4.", &members,
"http://anglebug.com/7527"};
FeatureInfo disableClipCullDistance = {"disableClipCullDistance",
FeatureCategory::OpenGLWorkarounds,
"Shader compiler does not handle redeclared built-ins.",
&members, "https://anglebug.com/7763"};
FeatureInfo emulateClipDistanceState = {
"emulateClipDistanceState",
FeatureCategory::OpenGLWorkarounds,
"Some drivers ignore GL_CLIP_DISTANCEi_EXT state.",
&members,
};
FeatureInfo supportsFragmentShaderInterlockNV = {
"supportsFragmentShaderInterlockNV", FeatureCategory::OpenGLFeatures,

Просмотреть файл

@ -645,12 +645,11 @@
"issue": "http://anglebug.com/7527"
},
{
"name": "disable_clip_cull_distance",
"name": "emulate_clip_distance_state",
"category": "Workarounds",
"description": [
"Shader compiler does not handle redeclared built-ins."
],
"issue": "https://anglebug.com/7763"
"Some drivers ignore GL_CLIP_DISTANCEi_EXT state."
]
},
{
"name": "supports_fragment_shader_interlock_NV",

Просмотреть файл

@ -2,7 +2,7 @@
"include/platform/FeaturesD3D_autogen.h":
"9923fb44d0a6f31948d0c8f46ee1d9e2",
"include/platform/FeaturesGL_autogen.h":
"a795a806d71b0e6d1f9e6d95c6e11971",
"38325ab28fca006d06f46d1ad4ad2d63",
"include/platform/FeaturesMtl_autogen.h":
"407426c8874de9295482ace9c94bd812",
"include/platform/FeaturesVk_autogen.h":
@ -16,13 +16,13 @@
"include/platform/gen_features.py":
"062989f7a8f3ff3b383f98fc8908dc33",
"include/platform/gl_features.json":
"3335055a70e35ebb7bf74c6d7c58897b",
"83005189979f62258c7799ec6a6a7572",
"include/platform/mtl_features.json":
"c66d170e7a8eb3448030f4c423ed0133",
"include/platform/vk_features.json":
"416eed871c6297e3b85ba81e9835a23a",
"util/angle_features_autogen.cpp":
"af7d54fc0f89936e88e374767d7e35f6",
"43d036bacde0c3ded225766feed3c76b",
"util/angle_features_autogen.h":
"299c0d91e1a076d87a43d789908c8b51"
"da5c78289a21d6e3b413bc48eab98d66"
}

Просмотреть файл

@ -222,6 +222,8 @@ class TCompiler : public TShHandleBase
return mCullDistanceSize ? mCullDistanceSize : (mCullDistanceMaxIndex + 1);
}
bool hasClipDistance() const { return getClipDistanceArraySize() != 0; }
protected:
// Add emulated functions to the built-in function emulator.
virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,

Просмотреть файл

@ -731,6 +731,17 @@ const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle)
#endif // ANGLE_ENABLE_HLSL
}
bool HasClipDistanceInVertexShader(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getShaderType() == GL_VERTEX_SHADER && compiler->hasClipDistance();
}
bool HasDiscardInFragmentShader(const ShHandle handle)
{
ASSERT(handle);

Просмотреть файл

@ -10,8 +10,11 @@
#include "common/utilities.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/OutputESSL.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/tree_ops/DeclarePerVertexBlocks.h"
#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
#include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
#include "compiler/translator/util.h"
namespace sh
{
@ -84,12 +87,50 @@ bool TranslatorESSL::translate(TIntermBlock *root,
if (getShaderType() == GL_VERTEX_SHADER)
{
// Move gl_ClipDistance and/or gl_CullDistance redeclarations to gl_PerVertex.
if (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_clip_cull_distance) &&
areClipDistanceOrCullDistanceRedeclared() &&
!DeclarePerVertexBlocks(this, root, &getSymbolTable()))
// Emulate GL_CLIP_DISTANCEi_EXT state if needed
if (hasClipDistance() && compileOptions.emulateClipDistanceState)
{
return false;
constexpr const ImmutableString kClipDistanceEnabledName("angle_ClipDistanceEnabled");
const TType *type = StaticType::Get<EbtUInt, EbpLow, EvqUniform, 1, 1>();
const TVariable *clipDistanceEnabled = new TVariable(
&getSymbolTable(), kClipDistanceEnabledName, type, SymbolType::AngleInternal);
const TIntermSymbol *clipDistanceEnabledSymbol = new TIntermSymbol(clipDistanceEnabled);
// AngleInternal variables don't get collected
if (shouldCollectVariables(compileOptions))
{
ShaderVariable uniform;
uniform.name = kClipDistanceEnabledName.data();
uniform.mappedName = kClipDistanceEnabledName.data();
uniform.type = GLVariableType(*type);
uniform.precision = GLVariablePrecision(*type);
uniform.staticUse = true;
uniform.active = true;
uniform.binding = type->getLayoutQualifier().binding;
uniform.location = type->getLayoutQualifier().location;
uniform.offset = type->getLayoutQualifier().offset;
uniform.rasterOrdered = type->getLayoutQualifier().rasterOrdered;
uniform.readonly = type->getMemoryQualifier().readonly;
uniform.writeonly = type->getMemoryQualifier().writeonly;
mUniforms.push_back(uniform);
}
DeclareGlobalVariable(root, clipDistanceEnabled);
if (!ZeroDisabledClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
clipDistanceEnabledSymbol))
return false;
// The previous operation always redeclares gl_ClipDistance
if (!DeclarePerVertexBlocks(this, root, &getSymbolTable()))
return false;
}
else if (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_clip_cull_distance) &&
areClipDistanceOrCullDistanceRedeclared())
{
// When clip distance state emulation is not needed,
// the redeclared extension built-ins still should be moved to gl_PerVertex
if (!DeclarePerVertexBlocks(this, root, &getSymbolTable()))
return false;
}
}
@ -193,7 +234,8 @@ void TranslatorESSL::writeExtensionBehavior(const ShCompileOptions &compileOptio
continue;
}
else if (iter->first == TExtension::EXT_clip_cull_distance &&
areClipDistanceOrCullDistanceRedeclared())
(areClipDistanceOrCullDistanceRedeclared() ||
(hasClipDistance() && compileOptions.emulateClipDistanceState)))
{
sink << "#extension GL_EXT_clip_cull_distance : " << GetBehaviorString(iter->second)
<< "\n"

Просмотреть файл

@ -1338,7 +1338,8 @@ angle::Result Program::linkImpl(const Context *context)
gl::Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
if (vertexShader)
{
mState.mNumViews = vertexShader->getNumViews(context);
mState.mNumViews = vertexShader->getNumViews(context);
mState.mExecutable->mHasClipDistance = vertexShader->hasClipDistance();
mState.mSpecConstUsageBits |= vertexShader->getSpecConstUsageBits();
}

Просмотреть файл

@ -196,6 +196,7 @@ ProgramExecutable::ProgramExecutable()
mImageUniformRange(0, 0),
mAtomicCounterUniformRange(0, 0),
mFragmentInoutRange(0, 0),
mHasClipDistance(false),
mHasDiscard(false),
mEnablesPerSampleShading(false),
// [GL_EXT_geometry_shader] Table 20.22
@ -245,6 +246,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
mAtomicCounterBuffers(other.mAtomicCounterBuffers),
mShaderStorageBlocks(other.mShaderStorageBlocks),
mFragmentInoutRange(other.mFragmentInoutRange),
mHasClipDistance(other.mHasClipDistance),
mHasDiscard(other.mHasDiscard),
mEnablesPerSampleShading(other.mEnablesPerSampleShading),
mAdvancedBlendEquations(other.mAdvancedBlendEquations)
@ -295,6 +297,7 @@ void ProgramExecutable::reset(bool clearInfoLog)
mAtomicCounterUniformRange = RangeUI(0, 0);
mFragmentInoutRange = RangeUI(0, 0);
mHasClipDistance = false;
mHasDiscard = false;
mEnablesPerSampleShading = false;
mAdvancedBlendEquations.reset();
@ -328,6 +331,8 @@ void ProgramExecutable::load(bool isSeparable, gl::BinaryInputStream *stream)
unsigned int fragmentInoutRangeHigh = stream->readInt<uint32_t>();
mFragmentInoutRange = RangeUI(fragmentInoutRangeLow, fragmentInoutRangeHigh);
mHasClipDistance = stream->readBool();
mHasDiscard = stream->readBool();
mEnablesPerSampleShading = stream->readBool();
@ -561,6 +566,8 @@ void ProgramExecutable::save(bool isSeparable, gl::BinaryOutputStream *stream) c
stream->writeInt(mFragmentInoutRange.low());
stream->writeInt(mFragmentInoutRange.high());
stream->writeBool(mHasClipDistance);
stream->writeBool(mHasDiscard);
stream->writeBool(mEnablesPerSampleShading);
stream->writeInt(mAdvancedBlendEquations.bits());

Просмотреть файл

@ -231,6 +231,7 @@ class ProgramExecutable final : public angle::Subject
const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; }
const RangeUI &getFragmentInoutRange() const { return mFragmentInoutRange; }
bool hasClipDistance() const { return mHasClipDistance; }
bool hasDiscard() const { return mHasDiscard; }
bool enablesPerSampleShading() const { return mEnablesPerSampleShading; }
BlendEquationBitSet getAdvancedBlendEquations() const { return mAdvancedBlendEquations; }
@ -473,6 +474,7 @@ class ProgramExecutable final : public angle::Subject
std::vector<InterfaceBlock> mShaderStorageBlocks;
RangeUI mFragmentInoutRange;
bool mHasClipDistance;
bool mHasDiscard;
bool mEnablesPerSampleShading;

Просмотреть файл

@ -396,6 +396,7 @@ void Shader::compile(const Context *context)
mState.mTessGenVertexOrder = 0;
mState.mTessGenPointMode = 0;
mState.mAdvancedBlendEquations.reset();
mState.mHasClipDistance = false;
mState.mHasDiscard = false;
mState.mEnablesPerSampleShading = false;
mState.mSpecConstUsageBits.reset();
@ -607,6 +608,7 @@ void Shader::resolveCompile(const Context *context)
mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle));
mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes);
mState.mHasClipDistance = sh::HasClipDistanceInVertexShader(compilerHandle);
mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle);
break;
}

Просмотреть файл

@ -95,6 +95,7 @@ class ShaderState final : angle::NonCopyable
const sh::WorkGroupSize &getLocalSize() const { return mLocalSize; }
bool hasClipDistance() const { return mHasClipDistance; }
bool hasDiscard() const { return mHasDiscard; }
bool enablesPerSampleShading() const { return mEnablesPerSampleShading; }
rx::SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; }
@ -139,6 +140,7 @@ class ShaderState final : angle::NonCopyable
std::vector<sh::ShaderVariable> mActiveAttributes;
std::vector<sh::ShaderVariable> mActiveOutputVariables;
bool mHasClipDistance;
bool mHasDiscard;
bool mEnablesPerSampleShading;
BlendEquationBitSet mAdvancedBlendEquations;
@ -212,6 +214,7 @@ class Shader final : angle::NonCopyable, public LabeledObject
unsigned int getRefCount() const;
bool isFlaggedForDeletion() const;
void flagForDeletion();
bool hasClipDistance() const { return mState.mHasClipDistance; }
bool hasDiscard() const { return mState.mHasDiscard; }
bool enablesPerSampleShading() const { return mState.mEnablesPerSampleShading; }
BlendEquationBitSet getAdvancedBlendEquations() const { return mState.mAdvancedBlendEquations; }

Просмотреть файл

@ -40,6 +40,7 @@ ProgramGL::ProgramGL(const gl::ProgramState &data,
mFeatures(features),
mStateManager(stateManager),
mHasAppliedTransformFeedbackVaryings(false),
mClipDistanceEnabledUniformLocation(-1),
mMultiviewBaseViewLayerIndexUniformLocation(-1),
mProgramID(0),
mRenderer(renderer),
@ -966,6 +967,7 @@ void ProgramGL::preLink()
mUniformRealLocationMap.clear();
mUniformBlockRealLocationMap.clear();
mClipDistanceEnabledUniformLocation = -1;
mMultiviewBaseViewLayerIndexUniformLocation = -1;
}
@ -1039,6 +1041,14 @@ void ProgramGL::postLink()
mUniformRealLocationMap[uniformLocation] = realLocation;
}
if (mFeatures.emulateClipDistanceState.enabled && mState.getExecutable().hasClipDistance())
{
ASSERT(mFunctions->standard == STANDARD_GL_ES);
mClipDistanceEnabledUniformLocation =
mFunctions->getUniformLocation(mProgramID, "angle_ClipDistanceEnabled");
ASSERT(mClipDistanceEnabledUniformLocation != -1);
}
if (mState.usesMultiview())
{
mMultiviewBaseViewLayerIndexUniformLocation =
@ -1047,6 +1057,16 @@ void ProgramGL::postLink()
}
}
void ProgramGL::updateEnabledClipDistances(uint8_t enabledClipDistancesPacked) const
{
ASSERT(mState.getExecutable().hasClipDistance());
ASSERT(mClipDistanceEnabledUniformLocation != -1);
ASSERT(mFunctions->programUniform1ui != nullptr);
mFunctions->programUniform1ui(mProgramID, mClipDistanceEnabledUniformLocation,
enabledClipDistancesPacked);
}
void ProgramGL::enableSideBySideRenderingPath() const
{
ASSERT(mState.usesMultiview());

Просмотреть файл

@ -108,6 +108,8 @@ class ProgramGL : public ProgramImpl
ANGLE_INLINE GLuint getProgramID() const { return mProgramID; }
void updateEnabledClipDistances(uint8_t enabledClipDistancesPacked) const;
void enableSideBySideRenderingPath() const;
void enableLayeredRenderingPath(int baseViewIndex) const;
@ -154,6 +156,8 @@ class ProgramGL : public ProgramImpl
bool mHasAppliedTransformFeedbackVaryings;
GLint mClipDistanceEnabledUniformLocation;
GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID;

Просмотреть файл

@ -376,6 +376,11 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
options->passHighpToPackUnormSnormBuiltins = true;
}
if (features.emulateClipDistanceState.enabled)
{
options->emulateClipDistanceState = true;
}
if (mRenderer->getNativeExtensions().shaderPixelLocalStorageANGLE)
{
options->pls = mRenderer->getNativePixelLocalStorageOptions();

Просмотреть файл

@ -2104,6 +2104,12 @@ angle::Result StateManagerGL::syncState(const gl::Context *context,
updateMultiviewBaseViewLayerIndexUniform(
program, state.getDrawFramebuffer()->getImplementation()->getState());
}
if (mFeatures.emulateClipDistanceState.enabled)
{
updateEmulatedClipDistanceState(executable, program,
state.getEnabledClipDistances());
}
}
if (!program ||
@ -2189,6 +2195,12 @@ angle::Result StateManagerGL::syncState(const gl::Context *context,
{
case gl::State::EXTENDED_DIRTY_BIT_CLIP_DISTANCES:
setClipDistancesEnable(state.getEnabledClipDistances());
if (mFeatures.emulateClipDistanceState.enabled)
{
updateEmulatedClipDistanceState(state.getProgramExecutable(),
state.getProgram(),
state.getEnabledClipDistances());
}
break;
case gl::State::EXTENDED_DIRTY_BIT_LOGIC_OP_ENABLED:
setLogicOpEnabled(state.isLogicOpEnabled());
@ -2538,6 +2550,19 @@ void StateManagerGL::updateMultiviewBaseViewLayerIndexUniformImpl(
}
}
void StateManagerGL::updateEmulatedClipDistanceState(
const gl::ProgramExecutable *executable,
const gl::Program *program,
const gl::State::ClipDistanceEnableBits enables) const
{
ASSERT(mFeatures.emulateClipDistanceState.enabled);
if (executable && executable->hasClipDistance())
{
const ProgramGL *programGL = GetImplAs<ProgramGL>(program);
programGL->updateEnabledClipDistances(static_cast<uint8_t>(enables.bits()));
}
}
void StateManagerGL::syncSamplersState(const gl::Context *context)
{
const gl::SamplerBindingVector &samplers = context->getState().getSamplers();

Просмотреть файл

@ -329,6 +329,10 @@ class StateManagerGL final : angle::NonCopyable
void syncSamplersState(const gl::Context *context);
void syncTransformFeedbackState(const gl::Context *context);
void updateEmulatedClipDistanceState(const gl::ProgramExecutable *executable,
const gl::Program *program,
const gl::State::ClipDistanceEnableBits enables) const;
void updateMultiviewBaseViewLayerIndexUniformImpl(
const gl::Program *program,
const gl::FramebufferState &drawFramebufferState) const;

Просмотреть файл

@ -1943,12 +1943,11 @@ void GenerateCaps(const FunctionsGL *functions,
// GL_EXT_clip_cull_distance spec requires shader interface blocks to support
// built-in array redeclarations on OpenGL ES.
extensions->clipCullDistanceEXT = !features.disableClipCullDistance.enabled &&
(functions->isAtLeastGL(gl::Version(4, 5)) ||
(functions->isAtLeastGL(gl::Version(3, 0)) &&
functions->hasGLExtension("GL_ARB_cull_distance")) ||
(extensions->shaderIoBlocksEXT &&
functions->hasGLESExtension("GL_EXT_clip_cull_distance")));
extensions->clipCullDistanceEXT =
functions->isAtLeastGL(gl::Version(4, 5)) ||
(functions->isAtLeastGL(gl::Version(3, 0)) &&
functions->hasGLExtension("GL_ARB_cull_distance")) ||
(extensions->shaderIoBlocksEXT && functions->hasGLESExtension("GL_EXT_clip_cull_distance"));
if (extensions->clipCullDistanceEXT)
{
caps->maxClipDistances = QuerySingleGLInt(functions, GL_MAX_CLIP_DISTANCES_EXT);
@ -2437,8 +2436,8 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
// https://anglebug.com/7527
ANGLE_FEATURE_CONDITION(features, passHighpToPackUnormSnormBuiltins, isQualcomm);
// https://anglebug.com/7763
ANGLE_FEATURE_CONDITION(features, disableClipCullDistance, isQualcomm);
// https://anglebug.com/7880
ANGLE_FEATURE_CONDITION(features, emulateClipDistanceState, isQualcomm);
// Desktop GLSL-only fragment synchronization extensions. These are injected internally by the
// compiler to make pixel local storage coherent.

Просмотреть файл

@ -66,7 +66,6 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
{Feature::DisableAnisotropicFiltering, "disableAnisotropicFiltering"},
{Feature::DisableB5G6R5Support, "disableB5G6R5Support"},
{Feature::DisableBlendFuncExtended, "disableBlendFuncExtended"},
{Feature::DisableClipCullDistance, "disableClipCullDistance"},
{Feature::DisableDrawBuffersIndexed, "disableDrawBuffersIndexed"},
{Feature::DisableFlippingBlitWithCommand, "disableFlippingBlitWithCommand"},
{Feature::DisableGPUSwitchingSupport, "disableGPUSwitchingSupport"},
@ -96,6 +95,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
{Feature::EmulateAbsIntFunction, "emulateAbsIntFunction"},
{Feature::EmulateAdvancedBlendEquations, "emulateAdvancedBlendEquations"},
{Feature::EmulateAtan2Float, "emulateAtan2Float"},
{Feature::EmulateClipDistanceState, "emulateClipDistanceState"},
{Feature::EmulateCopyTexImage2D, "emulateCopyTexImage2D"},
{Feature::EmulateCopyTexImage2DFromRenderbuffers, "emulateCopyTexImage2DFromRenderbuffers"},
{Feature::EmulateDithering, "emulateDithering"},

Просмотреть файл

@ -63,7 +63,6 @@ enum class Feature
DisableAnisotropicFiltering,
DisableB5G6R5Support,
DisableBlendFuncExtended,
DisableClipCullDistance,
DisableDrawBuffersIndexed,
DisableFlippingBlitWithCommand,
DisableGPUSwitchingSupport,
@ -90,6 +89,7 @@ enum class Feature
EmulateAbsIntFunction,
EmulateAdvancedBlendEquations,
EmulateAtan2Float,
EmulateClipDistanceState,
EmulateCopyTexImage2D,
EmulateCopyTexImage2DFromRenderbuffers,
EmulateDithering,