Hash :
98c2e169
Author :
Date :
2022-05-20T16:17:49
Vulkan: Reduce pre-rotation spec const to bool The specialization constant now only dictates whether x and y should be swapped. The complete 8 possible states of rotation and y-flip are achieved by using this swap in combination with a driver uniform for x and y flip. Swapping is still a specialization constant to avoid degrading performance of dFdx/dFdy which otherwise would need both to be evaluated instead of one. On platforms which don't support pre-rotation, the specialization constant will never change and driver uniforms entirely govern y-flip. On platforms that do support pre-rotation, only two variations of the pipeline are needed. Bug: angleproject:7366 Change-Id: I73f84e89fa9349d2098fa5b21573aee57d93a30c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3663151 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Lingfeng Yang <lfy@google.com> Reviewed-by: Charlie Lao <cclao@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
//
// 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.
//
// RewriteSampleMaskVariable.cpp: Find any references to gl_SampleMask and gl_SampleMaskIn, and
// rewrite it with ANGLESampleMask or ANGLESampleMaskIn.
//
#include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/BuiltIn.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
namespace sh
{
namespace
{
constexpr int kMaxIndexForSampleMaskVar = 0;
constexpr int kFullSampleMask = 0xFFFFFFFF;
// Traverse the tree and collect the redeclaration and replace all non constant index references of
// gl_SampleMask or gl_SampleMaskIn with constant index references
class GLSampleMaskRelatedReferenceTraverser : public TIntermTraverser
{
public:
GLSampleMaskRelatedReferenceTraverser(const TIntermSymbol **redeclaredSymOut,
const ImmutableString &targetStr)
: TIntermTraverser(true, false, false),
mRedeclaredSym(redeclaredSymOut),
mTargetStr(targetStr)
{
*mRedeclaredSym = nullptr;
}
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
{
// If gl_SampleMask is redeclared, we need to collect its information
const TIntermSequence &sequence = *(node->getSequence());
if (sequence.size() != 1)
{
return true;
}
TIntermTyped *variable = sequence.front()->getAsTyped();
TIntermSymbol *symbol = variable->getAsSymbolNode();
if (symbol == nullptr || symbol->getName() != mTargetStr)
{
return true;
}
*mRedeclaredSym = symbol;
return true;
}
bool visitBinary(Visit visit, TIntermBinary *node) override
{
TOperator op = node->getOp();
if (op != EOpIndexDirect && op != EOpIndexIndirect)
{
return true;
}
TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
if (!left)
{
return true;
}
if (left->getName() != mTargetStr)
{
return true;
}
const TConstantUnion *constIdx = node->getRight()->getConstantValue();
if (!constIdx)
{
if (node->getRight()->hasSideEffects())
{
insertStatementInParentBlock(node->getRight());
}
queueReplacementWithParent(node, node->getRight(),
CreateIndexNode(kMaxIndexForSampleMaskVar),
OriginalNode::IS_DROPPED);
}
return true;
}
private:
const TIntermSymbol **mRedeclaredSym;
const ImmutableString mTargetStr;
};
} // anonymous namespace
ANGLE_NO_DISCARD bool RewriteSampleMask(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
const TIntermTyped *numSamplesUniform)
{
const TIntermSymbol *redeclaredGLSampleMask = nullptr;
GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMask,
ImmutableString("gl_SampleMask"));
root->traverse(&indexTraverser);
if (!indexTraverser.updateTree(compiler, root))
{
return false;
}
// Retrieve gl_SampleMask variable reference
// Search user redeclared it first
const TVariable *glSampleMaskVar = nullptr;
if (redeclaredGLSampleMask)
{
glSampleMaskVar = &redeclaredGLSampleMask->variable();
}
else
{
// User defined not found, find in built-in table
glSampleMaskVar = static_cast<const TVariable *>(symbolTable->findBuiltIn(
ImmutableString("gl_SampleMask"), compiler->getShaderVersion()));
}
if (!glSampleMaskVar)
{
return false;
}
// Current ANGLE assumes that the maximum number of samples is less than or equal to
// VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
const unsigned int arraySizeOfSampleMask = glSampleMaskVar->getType().getOutermostArraySize();
ASSERT(arraySizeOfSampleMask == 1);
TIntermSymbol *glSampleMaskSymbol = new TIntermSymbol(glSampleMaskVar);
// if (ANGLEUniforms.numSamples == 1)
// {
// gl_SampleMask[0] = int(0xFFFFFFFF);
// }
TIntermConstantUnion *singleSampleCount = CreateUIntNode(1);
TIntermBinary *equalTo =
new TIntermBinary(EOpEqual, numSamplesUniform->deepCopy(), singleSampleCount);
TIntermBlock *trueBlock = new TIntermBlock();
TIntermBinary *sampleMaskVar = new TIntermBinary(EOpIndexDirect, glSampleMaskSymbol->deepCopy(),
CreateIndexNode(kMaxIndexForSampleMaskVar));
TIntermConstantUnion *fullSampleMask = CreateIndexNode(kFullSampleMask);
TIntermBinary *assignment = new TIntermBinary(EOpAssign, sampleMaskVar, fullSampleMask);
trueBlock->appendStatement(assignment);
TIntermIfElse *multiSampleOrNot = new TIntermIfElse(equalTo, trueBlock, nullptr);
return RunAtTheEndOfShader(compiler, root, multiSampleOrNot, symbolTable);
}
ANGLE_NO_DISCARD bool RewriteSampleMaskIn(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
const TIntermSymbol *redeclaredGLSampleMaskIn = nullptr;
GLSampleMaskRelatedReferenceTraverser indexTraverser(&redeclaredGLSampleMaskIn,
ImmutableString("gl_SampleMaskIn"));
root->traverse(&indexTraverser);
if (!indexTraverser.updateTree(compiler, root))
{
return false;
}
// Retrieve gl_SampleMaskIn variable reference
const TVariable *glSampleMaskInVar = nullptr;
glSampleMaskInVar = static_cast<const TVariable *>(
symbolTable->findBuiltIn(ImmutableString("gl_SampleMaskIn"), compiler->getShaderVersion()));
if (!glSampleMaskInVar)
{
return false;
}
// Current ANGLE assumes that the maximum number of samples is less than or equal to
// VK_SAMPLE_COUNT_32_BIT. So, the size of gl_SampleMask array is always one.
const unsigned int arraySizeOfSampleMaskIn =
glSampleMaskInVar->getType().getOutermostArraySize();
ASSERT(arraySizeOfSampleMaskIn == 1);
return true;
}
} // namespace sh