tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TranslatorHLSL.cpp (12249B)


      1 //
      2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 #include "compiler/translator/TranslatorHLSL.h"
      8 
      9 #include "compiler/translator/OutputHLSL.h"
     10 #include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
     11 #include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
     12 #include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
     13 #include "compiler/translator/tree_ops/SplitSequenceOperator.h"
     14 #include "compiler/translator/tree_ops/d3d/AddDefaultReturnStatements.h"
     15 #include "compiler/translator/tree_ops/d3d/AggregateAssignArraysInSSBOs.h"
     16 #include "compiler/translator/tree_ops/d3d/AggregateAssignStructsInSSBOs.h"
     17 #include "compiler/translator/tree_ops/d3d/ArrayReturnValueToOutParameter.h"
     18 #include "compiler/translator/tree_ops/d3d/BreakVariableAliasingInInnerLoops.h"
     19 #include "compiler/translator/tree_ops/d3d/ExpandIntegerPowExpressions.h"
     20 #include "compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.h"
     21 #include "compiler/translator/tree_ops/d3d/RewriteAtomicFunctionExpressions.h"
     22 #include "compiler/translator/tree_ops/d3d/RewriteElseBlocks.h"
     23 #include "compiler/translator/tree_ops/d3d/RewriteExpressionsWithShaderStorageBlock.h"
     24 #include "compiler/translator/tree_ops/d3d/RewriteUnaryMinusOperatorInt.h"
     25 #include "compiler/translator/tree_ops/d3d/SeparateArrayConstructorStatements.h"
     26 #include "compiler/translator/tree_ops/d3d/SeparateArrayInitialization.h"
     27 #include "compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.h"
     28 #include "compiler/translator/tree_ops/d3d/UnfoldShortCircuitToIf.h"
     29 #include "compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.h"
     30 #include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
     31 
     32 namespace sh
     33 {
     34 
     35 TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
     36    : TCompiler(type, spec, output)
     37 {}
     38 
     39 bool TranslatorHLSL::translate(TIntermBlock *root,
     40                               const ShCompileOptions &compileOptions,
     41                               PerformanceDiagnostics *perfDiagnostics)
     42 {
     43    // A few transformations leave the tree in an inconsistent state.  For example, when unfolding
     44    // the short-circuit in the following function:
     45    //
     46    //     mediump float f(float a) { return a > 0 ? 0.0 : 1.0; }
     47    //
     48    // a temp variable is created to hold the result of the expression.  Currently the precision of
     49    // the return value of the function is not propagated to its return expressions.  Additionally,
     50    // an expression such as
     51    //
     52    //     cond ? gl_NumWorkGroups.x : gl_NumWorkGroups.y
     53    //
     54    // does not have a precision as the built-in does not specify a precision.
     55    //
     56    // Precision is not applicable to HLSL so fixing these issues are deferred.
     57    mValidateASTOptions.validatePrecision = false;
     58 
     59    const ShBuiltInResources &resources = getResources();
     60    int numRenderTargets                = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
     61    int maxDualSourceDrawBuffers =
     62        resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
     63 
     64    if (!sh::AddDefaultReturnStatements(this, root))
     65    {
     66        return false;
     67    }
     68 
     69    // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
     70    // may need to generate new statements from loop conditions or loop expressions.
     71    // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
     72    if (!SimplifyLoopConditions(
     73            this, root,
     74            IntermNodePatternMatcher::kExpressionReturningArray |
     75                IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
     76                IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
     77            &getSymbolTable()))
     78    {
     79        return false;
     80    }
     81 
     82    if (!SplitSequenceOperator(
     83            this, root,
     84            IntermNodePatternMatcher::kExpressionReturningArray |
     85                IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
     86                IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
     87            &getSymbolTable()))
     88    {
     89        return false;
     90    }
     91 
     92    // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
     93    if (!UnfoldShortCircuitToIf(this, root, &getSymbolTable()))
     94    {
     95        return false;
     96    }
     97 
     98    if (!SeparateArrayConstructorStatements(this, root))
     99    {
    100        return false;
    101    }
    102 
    103    if (getShaderVersion() >= 310)
    104    {
    105        // Do element-by-element assignments of arrays in SSBOs. This allows the D3D backend to use
    106        // RWByteAddressBuffer.Load() and .Store(), which only operate on values up to 16 bytes in
    107        // size. Note that this must be done before SeparateExpressionsReturningArrays.
    108        if (!sh::AggregateAssignArraysInSSBOs(this, root, &getSymbolTable()))
    109        {
    110            return false;
    111        }
    112        // Do field-by-field assignment of structs in SSBOs. This allows the D3D backend to use
    113        // RWByteAddressBuffer.Load() and .Store(), which only operate on values up to 16 bytes in
    114        // size.
    115        if (!sh::AggregateAssignStructsInSSBOs(this, root, &getSymbolTable()))
    116        {
    117            return false;
    118        }
    119    }
    120 
    121    if (!SeparateExpressionsReturningArrays(this, root, &getSymbolTable()))
    122    {
    123        return false;
    124    }
    125 
    126    // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
    127    if (!SeparateArrayInitialization(this, root))
    128    {
    129        return false;
    130    }
    131 
    132    // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
    133    // as a return value to use an out parameter to transfer the array data instead.
    134    if (!ArrayReturnValueToOutParameter(this, root, &getSymbolTable()))
    135    {
    136        return false;
    137    }
    138 
    139    if (!shouldRunLoopAndIndexingValidation(compileOptions))
    140    {
    141        // HLSL doesn't support dynamic indexing of vectors and matrices.
    142        if (!RemoveDynamicIndexingOfNonSSBOVectorOrMatrix(this, root, &getSymbolTable(),
    143                                                          perfDiagnostics))
    144        {
    145            return false;
    146        }
    147    }
    148 
    149    // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
    150    // use a vertex attribute as a condition, and some related computation in the else block.
    151    if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
    152    {
    153        if (!sh::RewriteElseBlocks(this, root, &getSymbolTable()))
    154        {
    155            return false;
    156        }
    157    }
    158 
    159    // Work around an HLSL compiler frontend aliasing optimization bug.
    160    // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
    161    // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
    162    // version and only apply the workaround if it is too old.
    163    if (!sh::BreakVariableAliasingInInnerLoops(this, root))
    164    {
    165        return false;
    166    }
    167 
    168    // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
    169    // introduce variable declarations inside the main scope of any switch statement. It cannot
    170    // result in no-op cases at the end of switch statements, because unreferenced variables
    171    // have already been pruned.
    172    if (!WrapSwitchStatementsInBlocks(this, root))
    173    {
    174        return false;
    175    }
    176 
    177    if (compileOptions.expandSelectHLSLIntegerPowExpressions)
    178    {
    179        if (!sh::ExpandIntegerPowExpressions(this, root, &getSymbolTable()))
    180        {
    181            return false;
    182        }
    183    }
    184 
    185    if (compileOptions.rewriteTexelFetchOffsetToTexelFetch)
    186    {
    187        if (!sh::RewriteTexelFetchOffset(this, root, getSymbolTable(), getShaderVersion()))
    188        {
    189            return false;
    190        }
    191    }
    192 
    193    if (compileOptions.rewriteIntegerUnaryMinusOperator && getShaderType() == GL_VERTEX_SHADER)
    194    {
    195        if (!sh::RewriteUnaryMinusOperatorInt(this, root))
    196        {
    197            return false;
    198        }
    199    }
    200 
    201    if (getShaderVersion() >= 310)
    202    {
    203        // Due to ssbo also can be used as the argument of atomic memory functions, we should put
    204        // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions.
    205        if (!sh::RewriteExpressionsWithShaderStorageBlock(this, root, &getSymbolTable()))
    206        {
    207            return false;
    208        }
    209        if (!sh::RewriteAtomicFunctionExpressions(this, root, &getSymbolTable(),
    210                                                  getShaderVersion()))
    211        {
    212            return false;
    213        }
    214    }
    215 
    216    mUniformBlockOptimizedMap.clear();
    217    mSlowCompilingUniformBlockSet.clear();
    218    // In order to get the exact maximum of slots are available for shader resources, which would
    219    // been bound with StructuredBuffer, we only translate uniform block with a large array member
    220    // into StructuredBuffer when shader version is 300.
    221    if (getShaderVersion() == 300 && compileOptions.allowTranslateUniformBlockToStructuredBuffer)
    222    {
    223        if (!sh::RecordUniformBlocksWithLargeArrayMember(root, mUniformBlockOptimizedMap,
    224                                                         mSlowCompilingUniformBlockSet))
    225        {
    226            return false;
    227        }
    228    }
    229 
    230    sh::OutputHLSL outputHLSL(
    231        getShaderType(), getShaderSpec(), getShaderVersion(), getExtensionBehavior(),
    232        getSourcePath(), getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
    233        compileOptions, getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics,
    234        mUniformBlockOptimizedMap, mShaderStorageBlocks, isEarlyFragmentTestsSpecified());
    235 
    236    outputHLSL.output(root, getInfoSink().obj);
    237 
    238    mShaderStorageBlockRegisterMap      = outputHLSL.getShaderStorageBlockRegisterMap();
    239    mUniformBlockRegisterMap            = outputHLSL.getUniformBlockRegisterMap();
    240    mUniformBlockUseStructuredBufferMap = outputHLSL.getUniformBlockUseStructuredBufferMap();
    241    mUniformRegisterMap                 = outputHLSL.getUniformRegisterMap();
    242    mReadonlyImage2DRegisterIndex       = outputHLSL.getReadonlyImage2DRegisterIndex();
    243    mImage2DRegisterIndex               = outputHLSL.getImage2DRegisterIndex();
    244    mUsedImage2DFunctionNames           = outputHLSL.getUsedImage2DFunctionNames();
    245 
    246    return true;
    247 }
    248 
    249 bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
    250 {
    251    // Not necessary when translating to HLSL.
    252    return false;
    253 }
    254 
    255 bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const
    256 {
    257    return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0);
    258 }
    259 
    260 unsigned int TranslatorHLSL::getShaderStorageBlockRegister(
    261    const std::string &shaderStorageBlockName) const
    262 {
    263    ASSERT(hasShaderStorageBlock(shaderStorageBlockName));
    264    return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second;
    265 }
    266 
    267 bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
    268 {
    269    return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
    270 }
    271 
    272 unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
    273 {
    274    ASSERT(hasUniformBlock(uniformBlockName));
    275    return mUniformBlockRegisterMap.find(uniformBlockName)->second;
    276 }
    277 
    278 const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
    279 {
    280    return &mUniformRegisterMap;
    281 }
    282 
    283 const std::set<std::string> *TranslatorHLSL::getSlowCompilingUniformBlockSet() const
    284 {
    285    return &mSlowCompilingUniformBlockSet;
    286 }
    287 
    288 unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
    289 {
    290    return mReadonlyImage2DRegisterIndex;
    291 }
    292 
    293 unsigned int TranslatorHLSL::getImage2DRegisterIndex() const
    294 {
    295    return mImage2DRegisterIndex;
    296 }
    297 
    298 const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const
    299 {
    300    return &mUsedImage2DFunctionNames;
    301 }
    302 
    303 bool TranslatorHLSL::shouldUniformBlockUseStructuredBuffer(
    304    const std::string &uniformBlockName) const
    305 {
    306    auto uniformBlockIter = mUniformBlockUseStructuredBufferMap.find(uniformBlockName);
    307    return uniformBlockIter != mUniformBlockUseStructuredBufferMap.end() &&
    308           uniformBlockIter->second;
    309 }
    310 
    311 }  // namespace sh