Commit 24f64249 by Charlie Lao Committed by Commit Bot

Vulkan: Track specialization constant usage bit and feedback to ctx

Right now context does not know which specialization constant is used by the shader. Whenever a specialization constant changes, we assume shader program is using it, we always reach into vulkan driver to ask for a new program. Instead we can track shader's usage of specialization constant so that context can utilize this information to avoid recompile pipeline program if an unused specialization constant has changed. This CL implements the plumbing the usage bits form compiler to program object, it does not actually utilize the usage bits to avoid unnecessary compilation yet. Bug: b/173461931 Change-Id: Iebc9d0638c17b1a282c8b6093ce6bae154246e57 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2542866Reviewed-by: 's avatarIan Elliott <ianelliott@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Charlie Lao <cclao@google.com>
parent 565f1b16
......@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 244
#define ANGLE_SH_VERSION 245
enum ShShaderSpec
{
......@@ -720,6 +720,9 @@ int GetVertexShaderNumViews(const ShHandle handle);
// Returns true if compiler has injected instructions for early fragment tests as an optimization
bool HasEarlyFragmentTestsOptimization(const ShHandle handle);
// Returns specialization constant usage bits
uint32_t GetShaderSpecConstUsageBits(const ShHandle handle);
// Returns true if the passed in variables pack in maxVectors followingthe packing rules from the
// GLSL 1.017 spec, Appendix A, section 7.
// Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS
......@@ -830,6 +833,16 @@ enum class SurfaceRotation : uint32_t
EnumCount = InvalidEnum,
};
enum class SpecConstUsage : uint32_t
{
LineRasterEmulation = 0,
YFlip = 1,
Rotation = 2,
InvalidEnum = 3,
EnumCount = InvalidEnum,
};
// Interface block name containing the aggregate default uniforms
extern const char kDefaultUniformsNameVS[];
extern const char kDefaultUniformsNameTCS[];
......
......@@ -16,6 +16,7 @@
#include <GLSLANG/ShaderVars.h>
#include "common/PackedEnums.h"
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/Diagnostics.h"
......@@ -36,6 +37,8 @@ class TParseContext;
class TranslatorHLSL;
#endif // ANGLE_ENABLE_HLSL
using SpecConstUsageBits = angle::PackedEnumBitSet<vk::SpecConstUsage, uint32_t>;
//
// Helper function to check if the shader type is GLSL.
//
......@@ -100,6 +103,7 @@ class TCompiler : public TShHandleBase
bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; }
bool isEarlyFragmentTestsOptimized() const { return mEarlyFragmentTestsOptimized; }
SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
......@@ -193,6 +197,9 @@ class TCompiler : public TShHandleBase
std::vector<sh::InterfaceBlock> mShaderStorageBlocks;
std::vector<sh::InterfaceBlock> mInBlocks;
// Specialization constant usage bits
SpecConstUsageBits mSpecConstUsageBits;
private:
// Initialize symbol-table with built-in symbols.
bool initBuiltInSymbolTable(const ShBuiltInResources &resources);
......
......@@ -543,6 +543,16 @@ bool HasEarlyFragmentTestsOptimization(const ShHandle handle)
return compiler->isEarlyFragmentTestsOptimized();
}
uint32_t GetShaderSpecConstUsageBits(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
if (compiler == nullptr)
{
return 0;
}
return compiler->getSpecConstUsageBits().bits();
}
bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector<ShaderVariable> &variables)
{
return CheckVariablesInPackingLimits(maxVectors, variables);
......
......@@ -850,6 +850,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{
return false;
}
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
}
bool hasGLFragColor = false;
......@@ -970,6 +971,7 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{
return false;
}
mSpecConstUsageBits.set(vk::SpecConstUsage::LineRasterEmulation);
}
// Add a macro to declare transform feedback buffers.
......@@ -1028,6 +1030,9 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
surfaceRotationSpecConst.outputLayoutString(sink);
// Gather specialization constant usage bits so that we can feedback to context.
mSpecConstUsageBits |= surfaceRotationSpecConst.getSpecConstUsageBits();
if (!validateAST(root))
{
return false;
......
......@@ -220,7 +220,7 @@ TIntermTyped *CreateFloatArrayWithRotationIndex(const Vec2EnumMap &valuesEnumMap
}
} // anonymous namespace
FlipRotateSpecConst::FlipRotateSpecConst() : mSpecConstSymbol(nullptr), mReferenced(false) {}
FlipRotateSpecConst::FlipRotateSpecConst() : mSpecConstSymbol(nullptr) {}
FlipRotateSpecConst::~FlipRotateSpecConst()
{
......@@ -241,7 +241,7 @@ void FlipRotateSpecConst::generateSymbol(TSymbolTable *symbolTable)
void FlipRotateSpecConst::outputLayoutString(TInfoSinkBase &sink) const
{
// Only emit specialized const layout string if it has been referenced.
if (mReferenced)
if (mUsageBits.any())
{
sink << "layout(constant_id="
<< static_cast<uint32_t>(vk::SpecializationConstantId::SurfaceRotation)
......@@ -255,7 +255,8 @@ TIntermTyped *FlipRotateSpecConst::getMultiplierXForDFdx()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
mUsageBits.set(vk::SpecConstUsage::Rotation);
return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 0, 1, mSpecConstSymbol);
}
......@@ -265,7 +266,8 @@ TIntermTyped *FlipRotateSpecConst::getMultiplierYForDFdx()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
mUsageBits.set(vk::SpecConstUsage::Rotation);
return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdx, 1, 1, mSpecConstSymbol);
}
......@@ -275,7 +277,8 @@ TIntermTyped *FlipRotateSpecConst::getMultiplierXForDFdy()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
mUsageBits.set(vk::SpecConstUsage::Rotation);
return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 0, 1, mSpecConstSymbol);
}
......@@ -285,7 +288,8 @@ TIntermTyped *FlipRotateSpecConst::getMultiplierYForDFdy()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
mUsageBits.set(vk::SpecConstUsage::Rotation);
return CreateFloatArrayWithRotationIndex(kRotatedFlipXYForDFdy, 1, 1, mSpecConstSymbol);
}
......@@ -295,7 +299,7 @@ TIntermTyped *FlipRotateSpecConst::getPreRotationMatrix()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::Rotation);
return GenerateMat2x2ArrayWithIndex(kPreRotationMatrices, mSpecConstSymbol);
}
......@@ -305,7 +309,7 @@ TIntermTyped *FlipRotateSpecConst::getFragRotationMatrix()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::Rotation);
return GenerateMat2x2ArrayWithIndex(kFragRotationMatrices, mSpecConstSymbol);
}
......@@ -315,7 +319,7 @@ TIntermTyped *FlipRotateSpecConst::getFlipXY()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
return CreateVec2ArrayWithIndex(kFlipXYValue, 1.0, mSpecConstSymbol);
}
......@@ -325,7 +329,7 @@ TIntermTyped *FlipRotateSpecConst::getNegFlipXY()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
return CreateVec2ArrayWithIndex(kFlipXYValue, -1.0, mSpecConstSymbol);
}
......@@ -335,7 +339,7 @@ TIntermTyped *FlipRotateSpecConst::getFlipY()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, 1, mSpecConstSymbol);
}
......@@ -345,7 +349,7 @@ TIntermTyped *FlipRotateSpecConst::getNegFlipY()
{
return nullptr;
}
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
return CreateFloatArrayWithRotationIndex(kFlipXYValue, 1, -1, mSpecConstSymbol);
}
......@@ -374,7 +378,8 @@ TIntermTyped *FlipRotateSpecConst::getFragRotationMultiplyFlipXY()
{vk::SurfaceRotation::FlippedRotated270Degrees,
CalcFragRotationMultiplyFlipXY(vk::SurfaceRotation::FlippedRotated270Degrees)}}};
mReferenced = true;
mUsageBits.set(vk::SpecConstUsage::YFlip);
mUsageBits.set(vk::SpecConstUsage::Rotation);
return CreateVec2ArrayWithIndex(kFragRotationMultiplyFlipXY, 1.0, mSpecConstSymbol);
}
......
......@@ -11,6 +11,7 @@
#define COMPILER_TRANSLATOR_TREEUTIL_FLIPROTATESPECCONST_H_
#include "common/angleutils.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/SymbolTable.h"
class TIntermTyped;
......@@ -40,11 +41,12 @@ class FlipRotateSpecConst
void generateSymbol(TSymbolTable *symbolTable);
void outputLayoutString(TInfoSinkBase &sink) const;
SpecConstUsageBits getSpecConstUsageBits() const { return mUsageBits; }
private:
TIntermSymbol *mSpecConstSymbol;
// True if mSpecConstSymbol has been used
bool mReferenced;
// Bit is set if YFlip or Rotation has been used
SpecConstUsageBits mUsageBits;
};
} // namespace sh
......
......@@ -1577,6 +1577,7 @@ angle::Result Program::linkImpl(const Context *context)
if (vertexShader)
{
mState.mNumViews = vertexShader->getNumViews();
mState.mSpecConstUsageBits |= vertexShader->getSpecConstUsageBits();
}
gl::Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
......@@ -1584,6 +1585,7 @@ angle::Result Program::linkImpl(const Context *context)
{
mState.mEarlyFramentTestsOptimization =
fragmentShader->hasEarlyFragmentTestsOptimization();
mState.mSpecConstUsageBits |= fragmentShader->getSpecConstUsageBits();
}
InitUniformBlockLinker(mState, &mState.mExecutable->getResources().uniformBlockLinker);
......@@ -1855,6 +1857,7 @@ void Program::unlink()
mState.mCachedBaseVertex = 0;
mState.mCachedBaseInstance = 0;
mState.mEarlyFramentTestsOptimization = false;
mState.mSpecConstUsageBits.reset();
mValidated = false;
......@@ -5174,6 +5177,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeInt(mState.mNumViews);
stream.writeBool(mState.mEarlyFramentTestsOptimization);
stream.writeInt(mState.mSpecConstUsageBits.bits());
stream.writeInt(mState.getProgramInputs().size());
for (const sh::ShaderVariable &attrib : mState.getProgramInputs())
......@@ -5372,6 +5376,7 @@ angle::Result Program::deserialize(const Context *context,
mState.mNumViews = stream.readInt<int>();
mState.mEarlyFramentTestsOptimization = stream.readBool();
mState.mSpecConstUsageBits = rx::SpecConstUsageBits(stream.readInt<uint32_t>());
size_t attribCount = stream.readInt<size_t>();
ASSERT(mState.mExecutable->getProgramInputs().empty());
......
......@@ -323,6 +323,7 @@ class ProgramState final : angle::NonCopyable
bool hasImages() const { return !getImageBindings().empty(); }
bool hasEarlyFragmentTestsOptimization() const { return mEarlyFramentTestsOptimization; }
rx::SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; }
bool isShaderMarkedForDetach(gl::ShaderType shaderType) const
{
......@@ -416,6 +417,7 @@ class ProgramState final : angle::NonCopyable
bool mBinaryRetrieveableHint;
bool mSeparable;
bool mEarlyFramentTestsOptimization;
rx::SpecConstUsageBits mSpecConstUsageBits;
// ANGLE_multiview.
int mNumViews;
......
......@@ -538,5 +538,4 @@ bool ProgramExecutable::isYUVOutput() const
{
return !isCompute() && mYUVOutput;
}
} // namespace gl
......@@ -156,6 +156,18 @@ void ProgramPipelineState::updateExecutableTextures()
}
}
rx::SpecConstUsageBits ProgramPipelineState::getSpecConstUsageBits() const
{
rx::SpecConstUsageBits specConstUsageBits;
for (const ShaderType shaderType : mExecutable->getLinkedShaderStages())
{
const Program *program = getShaderProgram(shaderType);
ASSERT(program);
specConstUsageBits |= program->getState().getSpecConstUsageBits();
}
return specConstUsageBits;
}
ProgramPipeline::ProgramPipeline(rx::GLImplFactory *factory, ProgramPipelineID handle)
: RefCountObject(factory->generateSerial(), handle),
mProgramPipelineImpl(factory->createProgramPipeline(mState)),
......
......@@ -65,6 +65,8 @@ class ProgramPipelineState final : angle::NonCopyable
void updateExecutableTextures();
rx::SpecConstUsageBits getSpecConstUsageBits() const;
private:
void useProgramStage(const Context *context,
ShaderType shaderType,
......
......@@ -319,6 +319,7 @@ void Shader::compile(const Context *context)
mState.mGeometryShaderMaxVertices.reset();
mState.mGeometryShaderInvocations = 1;
mState.mEarlyFragmentTestsOptimization = false;
mState.mSpecConstUsageBits.reset();
mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
mBoundCompiler.set(context, context->getCompiler());
......@@ -432,6 +433,8 @@ void Shader::resolveCompile()
mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle));
mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle));
mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle));
mState.mSpecConstUsageBits =
rx::SpecConstUsageBits(sh::GetShaderSpecConstUsageBits(compilerHandle));
switch (mState.mShaderType)
{
......
......@@ -90,6 +90,7 @@ class ShaderState final : angle::NonCopyable
const sh::WorkGroupSize &getLocalSize() const { return mLocalSize; }
bool getEarlyFragmentTestsOptimization() const { return mEarlyFragmentTestsOptimization; }
rx::SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; }
int getNumViews() const { return mNumViews; }
......@@ -131,6 +132,7 @@ class ShaderState final : angle::NonCopyable
std::vector<sh::ShaderVariable> mActiveOutputVariables;
bool mEarlyFragmentTestsOptimization;
rx::SpecConstUsageBits mSpecConstUsageBits;
// ANGLE_multiview.
int mNumViews;
......@@ -190,6 +192,7 @@ class Shader final : angle::NonCopyable, public LabeledObject
{
return mState.mEarlyFragmentTestsOptimization;
}
rx::SpecConstUsageBits getSpecConstUsageBits() const { return mState.mSpecConstUsageBits; }
int getShaderVersion();
......
......@@ -646,6 +646,7 @@ void SerializeShaderState(gl::BinaryOutputStream *bos, const gl::ShaderState &sh
SerializeShaderVariablesVector(bos, shaderState.getActiveOutputVariables());
bos->writeBool(shaderState.getEarlyFragmentTestsOptimization());
bos->writeInt(shaderState.getNumViews());
bos->writeInt(shaderState.getSpecConstUsageBits().bits());
if (shaderState.getGeometryShaderInputPrimitiveType().valid())
{
bos->writeEnum(shaderState.getGeometryShaderInputPrimitiveType().value());
......
......@@ -15,6 +15,7 @@
#include <limits>
#include <map>
#include "GLSLANG/ShaderLang.h"
#include "common/angleutils.h"
#include "common/utilities.h"
#include "libANGLE/angletypes.h"
......@@ -60,6 +61,8 @@ enum class SurfaceRotation
EnumCount = InvalidEnum,
};
using SpecConstUsageBits = angle::PackedEnumBitSet<sh::vk::SpecConstUsage, uint32_t>;
void RotateRectangle(const SurfaceRotation rotation,
const bool flipY,
const int framebufferWidth,
......
......@@ -288,6 +288,20 @@ ProgramVk *ProgramExecutableVk::getShaderProgram(const gl::State &glState,
return nullptr;
}
SpecConstUsageBits ProgramExecutableVk::getSpecConstUsageBits() const
{
if (mProgram)
{
return mProgram->getState().getSpecConstUsageBits();
}
else if (mProgramPipeline)
{
return mProgramPipeline->getState().getSpecConstUsageBits();
}
return SpecConstUsageBits();
}
// TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into
// the ProgramExecutable, so this function can be removed.
void ProgramExecutableVk::fillProgramStateMap(
......
......@@ -181,6 +181,8 @@ class ProgramExecutableVk
const PerfCounters getObjectPerfCounters() const { return mObjectPerfCounters; }
SpecConstUsageBits getSpecConstUsageBits() const;
private:
friend class ProgramVk;
friend class ProgramPipelineVk;
......
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