Commit dee4d7a5 by Charlie Lao Committed by Commit Bot

Vulkan: Early fragment tests optimization

Checks if early fragment tests as an optimization is feasible and enable it if we can. In the link time, if context state diagrees with optimization (in rare case), then remove the ExecutionModeEarlyFragmentTests sprv op code. Bug: angleproject:4508 Change-Id: Ifbb06c0ffb050a9f3ddb16ab50362e908b4b9cf6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2136490 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com>
parent 32457326
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 227 #define ANGLE_SH_VERSION 228
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -336,6 +336,9 @@ const ShCompileOptions SH_REWRITE_ROW_MAJOR_MATRICES = UINT64_C(1) << 53; ...@@ -336,6 +336,9 @@ const ShCompileOptions SH_REWRITE_ROW_MAJOR_MATRICES = UINT64_C(1) << 53;
// Drop any explicit precision qualifiers from shader. // Drop any explicit precision qualifiers from shader.
const ShCompileOptions SH_IGNORE_PRECISION_QUALIFIERS = UINT64_C(1) << 54; const ShCompileOptions SH_IGNORE_PRECISION_QUALIFIERS = UINT64_C(1) << 54;
// Allow compiler to do early fragment tests as an optimization.
const ShCompileOptions SH_EARLY_FRAGMENT_TESTS_OPTIMIZATION = UINT64_C(1) << 55;
// Defines alternate strategies for implementing array index clamping. // Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy enum ShArrayIndexClampingStrategy
{ {
...@@ -665,6 +668,8 @@ sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle); ...@@ -665,6 +668,8 @@ sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle);
// Returns the number of views specified through the num_views layout qualifier. If num_views is // Returns the number of views specified through the num_views layout qualifier. If num_views is
// not set, the function returns -1. // not set, the function returns -1.
int GetVertexShaderNumViews(const ShHandle handle); 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 true if the passed in variables pack in maxVectors followingthe packing rules from the // Returns true if the passed in variables pack in maxVectors followingthe packing rules from the
// GLSL 1.017 spec, Appendix A, section 7. // GLSL 1.017 spec, Appendix A, section 7.
......
...@@ -124,6 +124,8 @@ angle_translator_sources = [ ...@@ -124,6 +124,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h", "src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h",
"src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp", "src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp",
"src/compiler/translator/tree_ops/DeferGlobalInitializers.h", "src/compiler/translator/tree_ops/DeferGlobalInitializers.h",
"src/compiler/translator/tree_ops/EarlyFragmentTestsOptimization.cpp",
"src/compiler/translator/tree_ops/EarlyFragmentTestsOptimization.h",
"src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp", "src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp",
"src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h", "src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h",
"src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp", "src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "compiler/translator/tree_ops/ClampPointSize.h" #include "compiler/translator/tree_ops/ClampPointSize.h"
#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h" #include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h"
#include "compiler/translator/tree_ops/DeferGlobalInitializers.h" #include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
#include "compiler/translator/tree_ops/EarlyFragmentTestsOptimization.h"
#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h" #include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h" #include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h"
#include "compiler/translator/tree_ops/EmulatePrecision.h" #include "compiler/translator/tree_ops/EmulatePrecision.h"
...@@ -930,6 +931,16 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, ...@@ -930,6 +931,16 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
} }
} }
mEarlyFragmentTestsOptimized = false;
if (compileOptions & SH_EARLY_FRAGMENT_TESTS_OPTIMIZATION)
{
if (mShaderVersion <= 300 && mShaderType == GL_FRAGMENT_SHADER &&
!isEarlyFragmentTestsSpecified())
{
mEarlyFragmentTestsOptimized = CheckEarlyFragmentTestsFeasible(this, root);
}
}
return true; return true;
} }
...@@ -1492,7 +1503,7 @@ bool TCompiler::isVaryingDefined(const char *varyingName) ...@@ -1492,7 +1503,7 @@ bool TCompiler::isVaryingDefined(const char *varyingName)
void EmitEarlyFragmentTestsGLSL(const TCompiler &compiler, TInfoSinkBase &sink) void EmitEarlyFragmentTestsGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
{ {
if (compiler.isEarlyFragmentTestsSpecified()) if (compiler.isEarlyFragmentTestsSpecified() || compiler.isEarlyFragmentTestsOptimized())
{ {
sink << "layout (early_fragment_tests) in;\n"; sink << "layout (early_fragment_tests) in;\n";
} }
......
...@@ -99,6 +99,7 @@ class TCompiler : public TShHandleBase ...@@ -99,6 +99,7 @@ class TCompiler : public TShHandleBase
TInfoSink &getInfoSink() { return mInfoSink; } TInfoSink &getInfoSink() { return mInfoSink; }
bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; } bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; }
bool isEarlyFragmentTestsOptimized() const { return mEarlyFragmentTestsOptimized; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
...@@ -278,6 +279,7 @@ class TCompiler : public TShHandleBase ...@@ -278,6 +279,7 @@ class TCompiler : public TShHandleBase
// fragment shader early fragment tests // fragment shader early fragment tests
bool mEarlyFragmentTestsSpecified; bool mEarlyFragmentTestsSpecified;
bool mEarlyFragmentTestsOptimized;
// compute shader local group size // compute shader local group size
bool mComputeShaderLocalSizeDeclared; bool mComputeShaderLocalSizeDeclared;
......
...@@ -499,6 +499,16 @@ int GetVertexShaderNumViews(const ShHandle handle) ...@@ -499,6 +499,16 @@ int GetVertexShaderNumViews(const ShHandle handle)
return compiler->getNumViews(); return compiler->getNumViews();
} }
bool HasEarlyFragmentTestsOptimization(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
if (compiler == nullptr)
{
return false;
}
return compiler->isEarlyFragmentTestsOptimized();
}
bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector<ShaderVariable> &variables) bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector<ShaderVariable> &variables)
{ {
return CheckVariablesInPackingLimits(maxVectors, variables); return CheckVariablesInPackingLimits(maxVectors, variables);
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CheckEarlyFragmentTestOptimization is an AST traverser to check if early fragment
// test as an optimization is feasible.
//
#include "compiler/translator/tree_ops/EarlyFragmentTestsOptimization.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Symbol.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
// Traverser that check conditions that would prevent early fragment tests optmization.
class CheckEFTOptimizationTraverser : public TIntermTraverser
{
public:
CheckEFTOptimizationTraverser();
void visitSymbol(TIntermSymbol *node) override;
bool visitBranch(Visit visit, TIntermBranch *node) override;
bool isFragDepthUsed() { return mFragDepthUsed; }
bool isDiscardOpUsed() { return mDiscardOpUsed; }
protected:
bool mFragDepthUsed;
bool mDiscardOpUsed;
};
CheckEFTOptimizationTraverser::CheckEFTOptimizationTraverser()
: TIntermTraverser(true, false, false), mFragDepthUsed(false), mDiscardOpUsed(false)
{}
void CheckEFTOptimizationTraverser::visitSymbol(TIntermSymbol *node)
{
// Check the qualifier from the variable, not from the symbol node. The node may have a
// different qualifier if it's the result of a folded ternary node.
TQualifier qualifier = node->variable().getType().getQualifier();
if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT)
{
mFragDepthUsed = true;
}
}
bool CheckEFTOptimizationTraverser::visitBranch(Visit visit, TIntermBranch *node)
{
if (node->getFlowOp() == EOpKill)
{
mDiscardOpUsed = true;
}
return true;
}
} // namespace
bool CheckEarlyFragmentTestsFeasible(TCompiler *compiler, TIntermNode *root)
{
CheckEFTOptimizationTraverser traverser;
root->traverse(&traverser);
if (traverser.isFragDepthUsed() || traverser.isDiscardOpUsed())
{
return false;
}
return true;
}
} // namespace sh
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CheckEarlyFragmentTestsOptimization is an AST traverser to check if early fragment
// tests as an optimization is feasible.
//
#ifndef COMPILER_TRANSLATOR_TREEOPS_EARLYFRAGMENTTESTSOPTIMIZATION_H_
#define COMPILER_TRANSLATOR_TREEOPS_EARLYFRAGMENTTESTSOPTIMIZATION_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermNode;
ANGLE_NO_DISCARD bool CheckEarlyFragmentTestsFeasible(TCompiler *compiler, TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_EARLYFRAGMENTTESTSOPTIMIZATION_H_
...@@ -1569,6 +1569,13 @@ angle::Result Program::link(const Context *context) ...@@ -1569,6 +1569,13 @@ angle::Result Program::link(const Context *context)
mState.mNumViews = vertexShader->getNumViews(); mState.mNumViews = vertexShader->getNumViews();
} }
gl::Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
if (fragmentShader)
{
mState.mEarlyFramentTestsOptimization =
fragmentShader->hasEarlyFragmentTestsOptimization();
}
InitUniformBlockLinker(mState, &mResources->uniformBlockLinker); InitUniformBlockLinker(mState, &mResources->uniformBlockLinker);
InitShaderStorageBlockLinker(mState, &mResources->shaderStorageBlockLinker); InitShaderStorageBlockLinker(mState, &mResources->shaderStorageBlockLinker);
...@@ -1824,6 +1831,7 @@ void Program::unlink() ...@@ -1824,6 +1831,7 @@ void Program::unlink()
mState.mBaseInstanceLocation = -1; mState.mBaseInstanceLocation = -1;
mState.mCachedBaseVertex = 0; mState.mCachedBaseVertex = 0;
mState.mCachedBaseInstance = 0; mState.mCachedBaseInstance = 0;
mState.mEarlyFramentTestsOptimization = false;
mValidated = false; mValidated = false;
...@@ -5054,6 +5062,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -5054,6 +5062,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeInt(mState.mGeometryShaderMaxVertices); stream.writeInt(mState.mGeometryShaderMaxVertices);
stream.writeInt(mState.mNumViews); stream.writeInt(mState.mNumViews);
stream.writeInt(mState.mEarlyFramentTestsOptimization);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8, static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each"); "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
...@@ -5253,7 +5262,8 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5253,7 +5262,8 @@ angle::Result Program::deserialize(const Context *context,
mState.mGeometryShaderInvocations = stream.readInt<int>(); mState.mGeometryShaderInvocations = stream.readInt<int>();
mState.mGeometryShaderMaxVertices = stream.readInt<int>(); mState.mGeometryShaderMaxVertices = stream.readInt<int>();
mState.mNumViews = stream.readInt<int>(); mState.mNumViews = stream.readInt<int>();
mState.mEarlyFramentTestsOptimization = stream.readInt<bool>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8, static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"Too many vertex attribs for mask: All bits of mAttributesTypeMask types and " "Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
......
...@@ -346,6 +346,7 @@ class ProgramState final : angle::NonCopyable ...@@ -346,6 +346,7 @@ class ProgramState final : angle::NonCopyable
{ {
return !getLinkedTransformFeedbackVaryings().empty(); return !getLinkedTransformFeedbackVaryings().empty();
} }
bool hasEarlyFragmentTestsOptimization() const { return mEarlyFramentTestsOptimization; }
bool isShaderMarkedForDetach(gl::ShaderType shaderType) const bool isShaderMarkedForDetach(gl::ShaderType shaderType) const
{ {
...@@ -428,6 +429,7 @@ class ProgramState final : angle::NonCopyable ...@@ -428,6 +429,7 @@ class ProgramState final : angle::NonCopyable
bool mBinaryRetrieveableHint; bool mBinaryRetrieveableHint;
bool mSeparable; bool mSeparable;
bool mEarlyFramentTestsOptimization;
// ANGLE_multiview. // ANGLE_multiview.
int mNumViews; int mNumViews;
......
...@@ -317,7 +317,8 @@ void Shader::compile(const Context *context) ...@@ -317,7 +317,8 @@ void Shader::compile(const Context *context)
mState.mGeometryShaderInputPrimitiveType.reset(); mState.mGeometryShaderInputPrimitiveType.reset();
mState.mGeometryShaderOutputPrimitiveType.reset(); mState.mGeometryShaderOutputPrimitiveType.reset();
mState.mGeometryShaderMaxVertices.reset(); mState.mGeometryShaderMaxVertices.reset();
mState.mGeometryShaderInvocations = 1; mState.mGeometryShaderInvocations = 1;
mState.mEarlyFragmentTestsOptimization = false;
mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED; mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
mBoundCompiler.set(context, context->getCompiler()); mBoundCompiler.set(context, context->getCompiler());
...@@ -490,6 +491,8 @@ void Shader::resolveCompile() ...@@ -490,6 +491,8 @@ void Shader::resolveCompile()
std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar);
mState.mActiveOutputVariables = mState.mActiveOutputVariables =
GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle));
mState.mEarlyFragmentTestsOptimization =
sh::HasEarlyFragmentTestsOptimization(compilerHandle);
break; break;
} }
case ShaderType::Geometry: case ShaderType::Geometry:
......
...@@ -85,6 +85,8 @@ class ShaderState final : angle::NonCopyable ...@@ -85,6 +85,8 @@ class ShaderState final : angle::NonCopyable
return mActiveOutputVariables; return mActiveOutputVariables;
} }
bool isEarlyFragmentTeststOptimization() const { return mEarlyFragmentTestsOptimization; }
bool compilePending() const { return mCompileStatus == CompileStatus::COMPILE_REQUESTED; } bool compilePending() const { return mCompileStatus == CompileStatus::COMPILE_REQUESTED; }
private: private:
...@@ -108,6 +110,8 @@ class ShaderState final : angle::NonCopyable ...@@ -108,6 +110,8 @@ class ShaderState final : angle::NonCopyable
std::vector<sh::ShaderVariable> mActiveAttributes; std::vector<sh::ShaderVariable> mActiveAttributes;
std::vector<sh::ShaderVariable> mActiveOutputVariables; std::vector<sh::ShaderVariable> mActiveOutputVariables;
bool mEarlyFragmentTestsOptimization;
// ANGLE_multiview. // ANGLE_multiview.
int mNumViews; int mNumViews;
...@@ -162,6 +166,10 @@ class Shader final : angle::NonCopyable, public LabeledObject ...@@ -162,6 +166,10 @@ class Shader final : angle::NonCopyable, public LabeledObject
unsigned int getRefCount() const; unsigned int getRefCount() const;
bool isFlaggedForDeletion() const; bool isFlaggedForDeletion() const;
void flagForDeletion(); void flagForDeletion();
bool hasEarlyFragmentTestsOptimization() const
{
return mState.mEarlyFragmentTestsOptimization;
}
int getShaderVersion(); int getShaderVersion();
......
...@@ -775,6 +775,8 @@ class State : angle::NonCopyable ...@@ -775,6 +775,8 @@ class State : angle::NonCopyable
return mNoSimultaneousConstantColorAndAlphaBlendFunc; return mNoSimultaneousConstantColorAndAlphaBlendFunc;
} }
bool isEarlyFragmentTestsOptimizationAllowed() const { return isSampleCoverageEnabled(); }
private: private:
friend class Context; friend class Context;
......
...@@ -978,6 +978,7 @@ class SpirvTransformer final : angle::NonCopyable ...@@ -978,6 +978,7 @@ class SpirvTransformer final : angle::NonCopyable
{ {
public: public:
SpirvTransformer(const std::vector<uint32_t> &spirvBlobIn, SpirvTransformer(const std::vector<uint32_t> &spirvBlobIn,
bool removeEarlyFragmentTestsOptimization,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderType shaderType, gl::ShaderType shaderType,
SpirvBlob *spirvBlobOut) SpirvBlob *spirvBlobOut)
...@@ -989,8 +990,8 @@ class SpirvTransformer final : angle::NonCopyable ...@@ -989,8 +990,8 @@ class SpirvTransformer final : angle::NonCopyable
{ {
gl::ShaderBitSet allStages; gl::ShaderBitSet allStages;
allStages.set(); allStages.set();
mRemoveEarlyFragmentTestsOptimization = removeEarlyFragmentTestsOptimization;
mBuiltinVariableInfo.activeStages = allStages; mBuiltinVariableInfo.activeStages = allStages;
} }
bool transform(); bool transform();
...@@ -1028,6 +1029,7 @@ class SpirvTransformer final : angle::NonCopyable ...@@ -1028,6 +1029,7 @@ class SpirvTransformer final : angle::NonCopyable
bool transformDecorate(const uint32_t *instruction, size_t wordCount); bool transformDecorate(const uint32_t *instruction, size_t wordCount);
bool transformTypePointer(const uint32_t *instruction, size_t wordCount); bool transformTypePointer(const uint32_t *instruction, size_t wordCount);
bool transformVariable(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);
// Any other instructions: // Any other instructions:
size_t copyInstruction(const uint32_t *instruction, size_t wordCount); size_t copyInstruction(const uint32_t *instruction, size_t wordCount);
...@@ -1038,6 +1040,8 @@ class SpirvTransformer final : angle::NonCopyable ...@@ -1038,6 +1040,8 @@ class SpirvTransformer final : angle::NonCopyable
const gl::ShaderType mShaderType; const gl::ShaderType mShaderType;
bool mHasTransformFeedbackOutput; bool mHasTransformFeedbackOutput;
bool mRemoveEarlyFragmentTestsOptimization;
// Input shader variable info map: // Input shader variable info map:
const ShaderInterfaceVariableInfoMap &mVariableInfoMap; const ShaderInterfaceVariableInfoMap &mVariableInfoMap;
ShaderInterfaceVariableInfo mBuiltinVariableInfo; ShaderInterfaceVariableInfo mBuiltinVariableInfo;
...@@ -1237,6 +1241,9 @@ void SpirvTransformer::transformInstruction() ...@@ -1237,6 +1241,9 @@ void SpirvTransformer::transformInstruction()
case spv::OpVariable: case spv::OpVariable:
transformed = transformVariable(instruction, wordCount); transformed = transformVariable(instruction, wordCount);
break; break;
case spv::OpExecutionMode:
transformed = transformExecutionMode(instruction, wordCount);
break;
default: default:
break; break;
} }
...@@ -1714,6 +1721,22 @@ bool SpirvTransformer::transformAccessChain(const uint32_t *instruction, size_t ...@@ -1714,6 +1721,22 @@ bool SpirvTransformer::transformAccessChain(const uint32_t *instruction, size_t
return true; return true;
} }
bool SpirvTransformer::transformExecutionMode(const uint32_t *instruction, size_t wordCount)
{
// SPIR-V 1.0 Section 3.32 Instructions, OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain,
// OpInBoundsPtrAccessChain
constexpr size_t kModeIndex = 2;
const uint32_t executionMode = instruction[kModeIndex];
if (executionMode == spv::ExecutionModeEarlyFragmentTests &&
mRemoveEarlyFragmentTestsOptimization)
{
// skip the copy
return true;
}
return false;
}
size_t SpirvTransformer::copyInstruction(const uint32_t *instruction, size_t wordCount) size_t SpirvTransformer::copyInstruction(const uint32_t *instruction, size_t wordCount)
{ {
size_t instructionOffset = mSpirvBlobOut->size(); size_t instructionOffset = mSpirvBlobOut->size();
...@@ -1921,6 +1944,7 @@ void GlslangGetShaderSource(GlslangSourceOptions &options, ...@@ -1921,6 +1944,7 @@ void GlslangGetShaderSource(GlslangSourceOptions &options,
angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback, angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool removeEarlyFragmentTestsOptimization,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
const SpirvBlob &initialSpirvBlob, const SpirvBlob &initialSpirvBlob,
SpirvBlob *spirvBlobOut) SpirvBlob *spirvBlobOut)
...@@ -1931,7 +1955,8 @@ angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback, ...@@ -1931,7 +1955,8 @@ angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback,
} }
// Transform the SPIR-V code by assigning location/set/binding values. // Transform the SPIR-V code by assigning location/set/binding values.
SpirvTransformer transformer(initialSpirvBlob, variableInfoMap, shaderType, spirvBlobOut); SpirvTransformer transformer(initialSpirvBlob, removeEarlyFragmentTestsOptimization,
variableInfoMap, shaderType, spirvBlobOut);
ANGLE_GLSLANG_CHECK(callback, transformer.transform(), GlslangError::InvalidSpirv); ANGLE_GLSLANG_CHECK(callback, transformer.transform(), GlslangError::InvalidSpirv);
ASSERT(ValidateSpirv(*spirvBlobOut)); ASSERT(ValidateSpirv(*spirvBlobOut));
...@@ -1950,8 +1975,12 @@ angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback, ...@@ -1950,8 +1975,12 @@ angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
for (const gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
// we pass in false here to skip modifications related to early fragment tests
// optimizations and line rasterization. These are done in the initProgram time since they
// are related to context state. We must keep original untouched spriv blobs here because we
// do not have ability to add back in at initProgram time.
angle::Result status = angle::Result status =
GlslangTransformSpirvCode(callback, shaderType, variableInfoMap[shaderType], GlslangTransformSpirvCode(callback, shaderType, false, variableInfoMap[shaderType],
initialSpirvBlobs[shaderType], &(*spirvBlobsOut)[shaderType]); initialSpirvBlobs[shaderType], &(*spirvBlobsOut)[shaderType]);
if (status != angle::Result::Continue) if (status != angle::Result::Continue)
{ {
......
...@@ -118,8 +118,9 @@ void GlslangGetShaderSource(GlslangSourceOptions &options, ...@@ -118,8 +118,9 @@ void GlslangGetShaderSource(GlslangSourceOptions &options,
angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback, angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool removeEarlyFragmentTestsOptimization,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
const std::vector<uint32_t> &initialSpirvBlob, const SpirvBlob &initialSpirvBlob,
SpirvBlob *spirvBlobOut); SpirvBlob *spirvBlobOut);
angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback, angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
......
...@@ -1189,6 +1189,7 @@ angle::Result ContextVk::handleDirtyGraphicsPipeline(const gl::Context *context, ...@@ -1189,6 +1189,7 @@ angle::Result ContextVk::handleDirtyGraphicsPipeline(const gl::Context *context,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
ASSERT(mExecutable); ASSERT(mExecutable);
mExecutable->updateEarlyFragmentTestsOptimization(this);
if (!mCurrentGraphicsPipeline) if (!mCurrentGraphicsPipeline)
{ {
...@@ -2706,6 +2707,9 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -2706,6 +2707,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
mGraphicsPipelineDesc->updateAlphaToCoverageEnable( mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
&mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled()); &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
ASSERT(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE >
gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED);
iter.setLaterBit(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
break; break;
case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
updateSampleMask(glState); updateSampleMask(glState);
......
...@@ -85,12 +85,13 @@ angle::Result GlslangWrapperVk::GetShaderCode( ...@@ -85,12 +85,13 @@ angle::Result GlslangWrapperVk::GetShaderCode(
angle::Result GlslangWrapperVk::TransformSpirV( angle::Result GlslangWrapperVk::TransformSpirV(
vk::Context *context, vk::Context *context,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool removeEarlyFragmentTestsOptimization,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
std::vector<uint32_t> &initialSpirvBlob, const SpirvBlob &initialSpirvBlob,
std::vector<uint32_t> *shaderCodeOut) SpirvBlob *shaderCodeOut)
{ {
return GlslangTransformSpirvCode( return GlslangTransformSpirvCode(
[context](GlslangError error) { return ErrorHandler(context, error); }, shaderType, [context](GlslangError error) { return ErrorHandler(context, error); }, shaderType,
variableInfoMap, initialSpirvBlob, shaderCodeOut); removeEarlyFragmentTestsOptimization, variableInfoMap, initialSpirvBlob, shaderCodeOut);
} }
} // namespace rx } // namespace rx
...@@ -45,9 +45,10 @@ class GlslangWrapperVk ...@@ -45,9 +45,10 @@ class GlslangWrapperVk
static angle::Result TransformSpirV(vk::Context *context, static angle::Result TransformSpirV(vk::Context *context,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool removeEarlyFragmentTestsOptimization,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
std::vector<uint32_t> &initialSpirvBlob, const SpirvBlob &initialSpirvBlob,
std::vector<uint32_t> *shaderCodeOut); SpirvBlob *shaderCodeOut);
}; };
} // namespace rx } // namespace rx
......
...@@ -88,7 +88,8 @@ ProgramInfo::~ProgramInfo() = default; ...@@ -88,7 +88,8 @@ ProgramInfo::~ProgramInfo() = default;
angle::Result ProgramInfo::initProgram(ContextVk *contextVk, angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
bool enableLineRasterEmulation) const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
ProgramTransformOptionBits optionBits)
{ {
const gl::ShaderMap<SpirvBlob> &spirvBlobs = shaderInfo.getSpirvBlobs(); const gl::ShaderMap<SpirvBlob> &spirvBlobs = shaderInfo.getSpirvBlobs();
...@@ -96,13 +97,28 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk, ...@@ -96,13 +97,28 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
if (!spirvBlob.empty()) if (!spirvBlob.empty())
{ {
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(), spirvBlob.data(), if (shaderType == gl::ShaderType::Fragment &&
spirvBlob.size() * sizeof(uint32_t))); optionBits[ProgramTransformOption::RemoveEarlyFragmentTestsOptimization])
{
SpirvBlob spirvBlobTransformed;
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, shaderType, true,
variableInfoMap[shaderType], spirvBlob,
&spirvBlobTransformed));
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
spirvBlobTransformed.data(),
spirvBlobTransformed.size() * sizeof(uint32_t)));
}
else
{
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
spirvBlob.data(),
spirvBlob.size() * sizeof(uint32_t)));
}
mProgramHelper.setShader(shaderType, &mShaders[shaderType]); mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
} }
if (enableLineRasterEmulation) if (optionBits[ProgramTransformOption::EnableLineRasterEmulation])
{ {
mProgramHelper.enableSpecializationConstant( mProgramHelper.enableSpecializationConstant(
sh::vk::SpecializationConstantId::LineRasterEmulation); sh::vk::SpecializationConstantId::LineRasterEmulation);
...@@ -148,6 +164,7 @@ void ProgramExecutableVk::reset(ContextVk *contextVk) ...@@ -148,6 +164,7 @@ void ProgramExecutableVk::reset(ContextVk *contextVk)
mEmptyDescriptorSets.fill(VK_NULL_HANDLE); mEmptyDescriptorSets.fill(VK_NULL_HANDLE);
mPipelineLayoutCreated = false; mPipelineLayoutCreated = false;
mNumDefaultUniformDescriptors = 0; mNumDefaultUniformDescriptors = 0;
mTransformOptionBits.reset();
for (vk::RefCountedDescriptorPoolBinding &binding : mDescriptorPoolBindings) for (vk::RefCountedDescriptorPoolBinding &binding : mDescriptorPoolBindings)
{ {
...@@ -162,8 +179,10 @@ void ProgramExecutableVk::reset(ContextVk *contextVk) ...@@ -162,8 +179,10 @@ void ProgramExecutableVk::reset(ContextVk *contextVk)
mTextureDescriptorsCache.clear(); mTextureDescriptorsCache.clear();
mDescriptorBuffersCache.clear(); mDescriptorBuffersCache.clear();
mDefaultProgramInfo.release(contextVk); for (ProgramInfo &programInfo : mProgramInfos)
mLineRasterProgramInfo.release(contextVk); {
programInfo.release(contextVk);
}
} }
std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *stream) std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *stream)
...@@ -529,6 +548,22 @@ void WriteBufferDescriptorSetBinding(const gl::OffsetBindingPointer<gl::Buffer> ...@@ -529,6 +548,22 @@ void WriteBufferDescriptorSetBinding(const gl::OffsetBindingPointer<gl::Buffer>
ASSERT(writeInfoOut->pBufferInfo[0].buffer != VK_NULL_HANDLE); ASSERT(writeInfoOut->pBufferInfo[0].buffer != VK_NULL_HANDLE);
} }
void ProgramExecutableVk::updateEarlyFragmentTestsOptimization(ContextVk *contextVk)
{
const gl::State &glState = contextVk->getState();
mTransformOptionBits[ProgramTransformOption::RemoveEarlyFragmentTestsOptimization] = false;
if (!glState.isEarlyFragmentTestsOptimizationAllowed())
{
ProgramVk *programVk = getShaderProgram(glState, gl::ShaderType::Fragment);
if (programVk->getState().hasEarlyFragmentTestsOptimization())
{
mTransformOptionBits[ProgramTransformOption::RemoveEarlyFragmentTestsOptimization] =
true;
}
}
}
angle::Result ProgramExecutableVk::getGraphicsPipeline( angle::Result ProgramExecutableVk::getGraphicsPipeline(
ContextVk *contextVk, ContextVk *contextVk,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
...@@ -537,9 +572,10 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline( ...@@ -537,9 +572,10 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline(
const vk::GraphicsPipelineDesc **descPtrOut, const vk::GraphicsPipelineDesc **descPtrOut,
vk::PipelineHelper **pipelineOut) vk::PipelineHelper **pipelineOut)
{ {
const gl::State &glState = contextVk->getState(); const gl::State &glState = contextVk->getState();
bool bresenhamEmulationEnabled = contextVk->isBresenhamEmulationEnabled(mode); mTransformOptionBits[ProgramTransformOption::EnableLineRasterEmulation] =
ProgramInfo &programInfo = getProgramInfo(bresenhamEmulationEnabled); contextVk->isBresenhamEmulationEnabled(mode);
ProgramInfo &programInfo = getProgramInfo(mTransformOptionBits);
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
vk::PipelineCache *pipelineCache = nullptr; vk::PipelineCache *pipelineCache = nullptr;
...@@ -552,7 +588,7 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline( ...@@ -552,7 +588,7 @@ angle::Result ProgramExecutableVk::getGraphicsPipeline(
if (programVk) if (programVk)
{ {
ANGLE_TRY(programVk->initGraphicsShaderProgram(contextVk, shaderType, ANGLE_TRY(programVk->initGraphicsShaderProgram(contextVk, shaderType,
bresenhamEmulationEnabled, programInfo)); mTransformOptionBits, programInfo));
} }
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ #ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_
#define LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ #define LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_
#include "common/bitset_utils.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/InfoLog.h" #include "libANGLE/InfoLog.h"
...@@ -45,6 +46,15 @@ class ShaderInfo final : angle::NonCopyable ...@@ -45,6 +46,15 @@ class ShaderInfo final : angle::NonCopyable
bool mIsInitialized = false; bool mIsInitialized = false;
}; };
enum class ProgramTransformOption : uint8_t
{
EnableLineRasterEmulation = 0,
RemoveEarlyFragmentTestsOptimization = 1,
EnumCount = 2,
PermutationCount = 4,
};
using ProgramTransformOptionBits = angle::PackedEnumBitSet<ProgramTransformOption, uint8_t>;
class ProgramInfo final : angle::NonCopyable class ProgramInfo final : angle::NonCopyable
{ {
public: public:
...@@ -54,7 +64,8 @@ class ProgramInfo final : angle::NonCopyable ...@@ -54,7 +64,8 @@ class ProgramInfo final : angle::NonCopyable
angle::Result initProgram(ContextVk *contextVk, angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
bool enableLineRasterEmulation); const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
ProgramTransformOptionBits optionBits);
void release(ContextVk *contextVk); void release(ContextVk *contextVk);
ANGLE_INLINE bool valid(const gl::ShaderType shaderType) const ANGLE_INLINE bool valid(const gl::ShaderType shaderType) const
...@@ -108,10 +119,10 @@ class ProgramExecutableVk ...@@ -108,10 +119,10 @@ class ProgramExecutableVk
gl::ShaderMap<const gl::ProgramState *> *programStatesOut); gl::ShaderMap<const gl::ProgramState *> *programStatesOut);
const gl::ProgramExecutable &getGlExecutable(); const gl::ProgramExecutable &getGlExecutable();
ProgramInfo &getDefaultProgramInfo() { return mDefaultProgramInfo; } ProgramInfo &getDefaultProgramInfo() { return mProgramInfos[0]; }
ProgramInfo &getProgramInfo(bool enableLineRasterEmulation) ProgramInfo &getProgramInfo(ProgramTransformOptionBits optionBits)
{ {
return enableLineRasterEmulation ? mLineRasterProgramInfo : mDefaultProgramInfo; return mProgramInfos[optionBits.to_ulong()];
} }
angle::Result getGraphicsPipeline(ContextVk *contextVk, angle::Result getGraphicsPipeline(ContextVk *contextVk,
...@@ -137,6 +148,8 @@ class ProgramExecutableVk ...@@ -137,6 +148,8 @@ class ProgramExecutableVk
angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer); angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
void updateEarlyFragmentTestsOptimization(ContextVk *contextVk);
void setProgram(ProgramVk *program) void setProgram(ProgramVk *program)
{ {
ASSERT(!mProgram && !mProgramPipeline); ASSERT(!mProgram && !mProgramPipeline);
...@@ -227,8 +240,9 @@ class ProgramExecutableVk ...@@ -227,8 +240,9 @@ class ProgramExecutableVk
// since that's slow to calculate. // since that's slow to calculate.
ShaderMapInterfaceVariableInfoMap mVariableInfoMap; ShaderMapInterfaceVariableInfoMap mVariableInfoMap;
ProgramInfo mDefaultProgramInfo; ProgramInfo mProgramInfos[static_cast<int>(ProgramTransformOption::PermutationCount)];
ProgramInfo mLineRasterProgramInfo;
ProgramTransformOptionBits mTransformOptionBits;
ProgramVk *mProgram; ProgramVk *mProgram;
ProgramPipelineVk *mProgramPipeline; ProgramPipelineVk *mProgramPipeline;
......
...@@ -106,8 +106,10 @@ angle::Result ProgramPipelineVk::transformShaderSpirV(const gl::Context *glConte ...@@ -106,8 +106,10 @@ angle::Result ProgramPipelineVk::transformShaderSpirV(const gl::Context *glConte
mExecutable.mVariableInfoMap[shaderType]; mExecutable.mVariableInfoMap[shaderType];
std::vector<uint32_t> transformedSpirvBlob; std::vector<uint32_t> transformedSpirvBlob;
// We skip early fragment tests optimization modification here since we need to keep
// original spriv blob here.
ANGLE_TRY(GlslangWrapperVk::TransformSpirV( ANGLE_TRY(GlslangWrapperVk::TransformSpirV(
contextVk, shaderType, variableInfoMap, contextVk, shaderType, false, variableInfoMap,
programVk->getShaderInfo().getSpirvBlobs()[shaderType], &transformedSpirvBlob)); programVk->getShaderInfo().getSpirvBlobs()[shaderType], &transformedSpirvBlob));
// Save the newly transformed SPIR-V // Save the newly transformed SPIR-V
......
...@@ -126,15 +126,16 @@ class ProgramVk : public ProgramImpl ...@@ -126,15 +126,16 @@ class ProgramVk : public ProgramImpl
ANGLE_INLINE angle::Result initGraphicsShaderProgram(ContextVk *contextVk, ANGLE_INLINE angle::Result initGraphicsShaderProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool enableLineRasterEmulation, ProgramTransformOptionBits optionBits,
ProgramInfo &programInfo) ProgramInfo &programInfo)
{ {
return initProgram(contextVk, shaderType, enableLineRasterEmulation, &programInfo); return initProgram(contextVk, shaderType, optionBits, &programInfo);
} }
ANGLE_INLINE angle::Result initComputeProgram(ContextVk *contextVk, ProgramInfo &programInfo) ANGLE_INLINE angle::Result initComputeProgram(ContextVk *contextVk, ProgramInfo &programInfo)
{ {
return initProgram(contextVk, gl::ShaderType::Compute, false, &programInfo); ProgramTransformOptionBits optionBits;
return initProgram(contextVk, gl::ShaderType::Compute, optionBits, &programInfo);
} }
ShaderInfo &getShaderInfo() { return mShaderInfo; } ShaderInfo &getShaderInfo() { return mShaderInfo; }
...@@ -169,7 +170,7 @@ class ProgramVk : public ProgramImpl ...@@ -169,7 +170,7 @@ class ProgramVk : public ProgramImpl
ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk, ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool enableLineRasterEmulation, ProgramTransformOptionBits optionBits,
ProgramInfo *programInfo) ProgramInfo *programInfo)
{ {
ASSERT(mShaderInfo.valid()); ASSERT(mShaderInfo.valid());
...@@ -179,7 +180,7 @@ class ProgramVk : public ProgramImpl ...@@ -179,7 +180,7 @@ class ProgramVk : public ProgramImpl
if (!programInfo->valid(shaderType)) if (!programInfo->valid(shaderType))
{ {
ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, mShaderInfo, ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, mShaderInfo,
enableLineRasterEmulation)); mExecutable.mVariableInfoMap, optionBits));
} }
ASSERT(programInfo->valid(shaderType)); ASSERT(programInfo->valid(shaderType));
......
...@@ -60,6 +60,10 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte ...@@ -60,6 +60,10 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte
compileOptions |= SH_IGNORE_PRECISION_QUALIFIERS; compileOptions |= SH_IGNORE_PRECISION_QUALIFIERS;
} }
// Let compiler detect and emit early fragment test execution mode. We will remove it if
// context state does not allow it
compileOptions |= SH_EARLY_FRAGMENT_TESTS_OPTIMIZATION;
return compileImpl(context, compilerInstance, mData.getSource(), compileOptions | options); return compileImpl(context, compilerInstance, mData.getSource(), compileOptions | options);
} }
......
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