LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - EmulatePrecision.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 284 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2002-2014 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/EmulatePrecision.h"
       8             : 
       9             : #include <memory>
      10             : 
      11             : namespace sh
      12             : {
      13             : 
      14             : namespace
      15             : {
      16             : 
      17             : class RoundingHelperWriter : angle::NonCopyable
      18             : {
      19             :   public:
      20             :     static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage);
      21             : 
      22             :     void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion);
      23             :     void writeCompoundAssignmentHelper(TInfoSinkBase &sink,
      24             :                                        const char *lType,
      25             :                                        const char *rType,
      26             :                                        const char *opStr,
      27             :                                        const char *opNameStr);
      28             : 
      29           0 :     virtual ~RoundingHelperWriter() {}
      30             : 
      31             :   protected:
      32           0 :     RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {}
      33             :     RoundingHelperWriter() = delete;
      34             : 
      35             :     const ShShaderOutput mOutputLanguage;
      36             : 
      37             :   private:
      38             :     virtual std::string getTypeString(const char *glslType)     = 0;
      39             :     virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0;
      40             :     virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0;
      41             :     virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink,
      42             :                                            const unsigned int columns,
      43             :                                            const unsigned int rows,
      44             :                                            const char *functionName) = 0;
      45             : };
      46             : 
      47           0 : class RoundingHelperWriterGLSL : public RoundingHelperWriter
      48             : {
      49             :   public:
      50           0 :     RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage)
      51           0 :         : RoundingHelperWriter(outputLanguage)
      52             :     {
      53           0 :     }
      54             : 
      55             :   private:
      56             :     std::string getTypeString(const char *glslType) override;
      57             :     void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
      58             :     void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
      59             :     void writeMatrixRoundingHelper(TInfoSinkBase &sink,
      60             :                                    const unsigned int columns,
      61             :                                    const unsigned int rows,
      62             :                                    const char *functionName) override;
      63             : };
      64             : 
      65           0 : class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL
      66             : {
      67             :   public:
      68           0 :     RoundingHelperWriterESSL(const ShShaderOutput outputLanguage)
      69           0 :         : RoundingHelperWriterGLSL(outputLanguage)
      70             :     {
      71           0 :     }
      72             : 
      73             :   private:
      74             :     std::string getTypeString(const char *glslType) override;
      75             : };
      76             : 
      77           0 : class RoundingHelperWriterHLSL : public RoundingHelperWriter
      78             : {
      79             :   public:
      80           0 :     RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage)
      81           0 :         : RoundingHelperWriter(outputLanguage)
      82             :     {
      83           0 :     }
      84             : 
      85             :   private:
      86             :     std::string getTypeString(const char *glslType) override;
      87             :     void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
      88             :     void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
      89             :     void writeMatrixRoundingHelper(TInfoSinkBase &sink,
      90             :                                    const unsigned int columns,
      91             :                                    const unsigned int rows,
      92             :                                    const char *functionName) override;
      93             : };
      94             : 
      95           0 : RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage)
      96             : {
      97           0 :     ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage));
      98           0 :     switch (outputLanguage)
      99             :     {
     100             :         case SH_HLSL_4_1_OUTPUT:
     101           0 :             return new RoundingHelperWriterHLSL(outputLanguage);
     102             :         case SH_ESSL_OUTPUT:
     103           0 :             return new RoundingHelperWriterESSL(outputLanguage);
     104             :         default:
     105           0 :             return new RoundingHelperWriterGLSL(outputLanguage);
     106             :     }
     107             : }
     108             : 
     109           0 : void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion)
     110             : {
     111             :     // Write the angle_frm functions that round floating point numbers to
     112             :     // half precision, and angle_frl functions that round them to minimum lowp
     113             :     // precision.
     114             : 
     115           0 :     writeFloatRoundingHelpers(sink);
     116           0 :     writeVectorRoundingHelpers(sink, 2);
     117           0 :     writeVectorRoundingHelpers(sink, 3);
     118           0 :     writeVectorRoundingHelpers(sink, 4);
     119           0 :     if (shaderVersion > 100)
     120             :     {
     121           0 :         for (unsigned int columns = 2; columns <= 4; ++columns)
     122             :         {
     123           0 :             for (unsigned int rows = 2; rows <= 4; ++rows)
     124             :             {
     125           0 :                 writeMatrixRoundingHelper(sink, columns, rows, "angle_frm");
     126           0 :                 writeMatrixRoundingHelper(sink, columns, rows, "angle_frl");
     127             :             }
     128             :         }
     129             :     }
     130             :     else
     131             :     {
     132           0 :         for (unsigned int size = 2; size <= 4; ++size)
     133             :         {
     134           0 :             writeMatrixRoundingHelper(sink, size, size, "angle_frm");
     135           0 :             writeMatrixRoundingHelper(sink, size, size, "angle_frl");
     136             :         }
     137             :     }
     138           0 : }
     139             : 
     140           0 : void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink,
     141             :                                                          const char *lType,
     142             :                                                          const char *rType,
     143             :                                                          const char *opStr,
     144             :                                                          const char *opNameStr)
     145             : {
     146           0 :     std::string lTypeStr = getTypeString(lType);
     147           0 :     std::string rTypeStr = getTypeString(rType);
     148             : 
     149             :     // Note that y should be passed through angle_frm at the function call site,
     150             :     // but x can't be passed through angle_frm there since it is an inout parameter.
     151             :     // So only pass x and the result through angle_frm here.
     152             :     // clang-format off
     153             :     sink <<
     154           0 :         lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
     155           0 :         "    x = angle_frm(angle_frm(x) " << opStr << " y);\n"
     156             :         "    return x;\n"
     157           0 :         "}\n";
     158             :     sink <<
     159           0 :         lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
     160           0 :         "    x = angle_frl(angle_frm(x) " << opStr << " y);\n"
     161             :         "    return x;\n"
     162           0 :         "}\n";
     163             :     // clang-format on
     164           0 : }
     165             : 
     166           0 : std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType)
     167             : {
     168           0 :     return glslType;
     169             : }
     170             : 
     171           0 : std::string RoundingHelperWriterESSL::getTypeString(const char *glslType)
     172             : {
     173           0 :     std::stringstream typeStrStr;
     174           0 :     typeStrStr << "highp " << glslType;
     175           0 :     return typeStrStr.str();
     176             : }
     177             : 
     178           0 : void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
     179             : {
     180             :     // Unoptimized version of angle_frm for single floats:
     181             :     //
     182             :     // int webgl_maxNormalExponent(in int exponentBits)
     183             :     // {
     184             :     //     int possibleExponents = int(exp2(float(exponentBits)));
     185             :     //     int exponentBias = possibleExponents / 2 - 1;
     186             :     //     int allExponentBitsOne = possibleExponents - 1;
     187             :     //     return (allExponentBitsOne - 1) - exponentBias;
     188             :     // }
     189             :     //
     190             :     // float angle_frm(in float x)
     191             :     // {
     192             :     //     int mantissaBits = 10;
     193             :     //     int exponentBits = 5;
     194             :     //     float possibleMantissas = exp2(float(mantissaBits));
     195             :     //     float mantissaMax = 2.0 - 1.0 / possibleMantissas;
     196             :     //     int maxNE = webgl_maxNormalExponent(exponentBits);
     197             :     //     float max = exp2(float(maxNE)) * mantissaMax;
     198             :     //     if (x > max)
     199             :     //     {
     200             :     //         return max;
     201             :     //     }
     202             :     //     if (x < -max)
     203             :     //     {
     204             :     //         return -max;
     205             :     //     }
     206             :     //     float exponent = floor(log2(abs(x)));
     207             :     //     if (abs(x) == 0.0 || exponent < -float(maxNE))
     208             :     //     {
     209             :     //         return 0.0 * sign(x)
     210             :     //     }
     211             :     //     x = x * exp2(-(exponent - float(mantissaBits)));
     212             :     //     x = sign(x) * floor(abs(x));
     213             :     //     return x * exp2(exponent - float(mantissaBits));
     214             :     // }
     215             : 
     216             :     // All numbers with a magnitude less than 2^-15 are subnormal, and are
     217             :     // flushed to zero.
     218             : 
     219             :     // Note the constant numbers below:
     220             :     // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times
     221             :     //    2^15, the maximum normal exponent.
     222             :     // b) 10.0 is the number of mantissa bits.
     223             :     // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number
     224             :     //    of mantissa bits.
     225             :     // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can
     226             :     //    only affect the result of log2 on x where abs(x) < 1e-22. Since these
     227             :     //    numbers will be flushed to zero either way (2^-15 is the smallest
     228             :     //    normal positive number), this does not introduce any error.
     229             : 
     230           0 :     std::string floatType = getTypeString("float");
     231             : 
     232             :     // clang-format off
     233             :     sink <<
     234           0 :         floatType << " angle_frm(in " << floatType << " x) {\n"
     235             :         "    x = clamp(x, -65504.0, 65504.0);\n"
     236           0 :         "    " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n"
     237             :         "    bool isNonZero = (exponent >= -25.0);\n"
     238             :         "    x = x * exp2(-exponent);\n"
     239             :         "    x = sign(x) * floor(abs(x));\n"
     240             :         "    return x * exp2(exponent) * float(isNonZero);\n"
     241           0 :         "}\n";
     242             : 
     243             :     sink <<
     244           0 :         floatType << " angle_frl(in " << floatType << " x) {\n"
     245             :         "    x = clamp(x, -2.0, 2.0);\n"
     246             :         "    x = x * 256.0;\n"
     247             :         "    x = sign(x) * floor(abs(x));\n"
     248             :         "    return x * 0.00390625;\n"
     249           0 :         "}\n";
     250             :     // clang-format on
     251           0 : }
     252             : 
     253           0 : void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
     254             :                                                           const unsigned int size)
     255             : {
     256           0 :     std::stringstream vecTypeStrStr;
     257           0 :     vecTypeStrStr << "vec" << size;
     258           0 :     std::string vecType = getTypeString(vecTypeStrStr.str().c_str());
     259             : 
     260             :     // clang-format off
     261             :     sink <<
     262           0 :         vecType << " angle_frm(in " << vecType << " v) {\n"
     263             :         "    v = clamp(v, -65504.0, 65504.0);\n"
     264           0 :         "    " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
     265           0 :         "    bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n"
     266             :         "    v = v * exp2(-exponent);\n"
     267             :         "    v = sign(v) * floor(abs(v));\n"
     268           0 :         "    return v * exp2(exponent) * vec" << size << "(isNonZero);\n"
     269           0 :         "}\n";
     270             : 
     271             :     sink <<
     272           0 :         vecType << " angle_frl(in " << vecType << " v) {\n"
     273             :         "    v = clamp(v, -2.0, 2.0);\n"
     274             :         "    v = v * 256.0;\n"
     275             :         "    v = sign(v) * floor(abs(v));\n"
     276             :         "    return v * 0.00390625;\n"
     277           0 :         "}\n";
     278             :     // clang-format on
     279           0 : }
     280             : 
     281           0 : void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
     282             :                                                          const unsigned int columns,
     283             :                                                          const unsigned int rows,
     284             :                                                          const char *functionName)
     285             : {
     286           0 :     std::stringstream matTypeStrStr;
     287           0 :     matTypeStrStr << "mat" << columns;
     288           0 :     if (rows != columns)
     289             :     {
     290           0 :         matTypeStrStr << "x" << rows;
     291             :     }
     292           0 :     std::string matType = getTypeString(matTypeStrStr.str().c_str());
     293             : 
     294           0 :     sink << matType << " " << functionName << "(in " << matType << " m) {\n"
     295           0 :          << "    " << matType << " rounded;\n";
     296             : 
     297           0 :     for (unsigned int i = 0; i < columns; ++i)
     298             :     {
     299           0 :         sink << "    rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
     300             :     }
     301             : 
     302             :     sink << "    return rounded;\n"
     303           0 :             "}\n";
     304           0 : }
     305             : 
     306           0 : static const char *GetHLSLTypeStr(const char *floatTypeStr)
     307             : {
     308           0 :     if (strcmp(floatTypeStr, "float") == 0)
     309             :     {
     310           0 :         return "float";
     311             :     }
     312           0 :     if (strcmp(floatTypeStr, "vec2") == 0)
     313             :     {
     314           0 :         return "float2";
     315             :     }
     316           0 :     if (strcmp(floatTypeStr, "vec3") == 0)
     317             :     {
     318           0 :         return "float3";
     319             :     }
     320           0 :     if (strcmp(floatTypeStr, "vec4") == 0)
     321             :     {
     322           0 :         return "float4";
     323             :     }
     324           0 :     if (strcmp(floatTypeStr, "mat2") == 0)
     325             :     {
     326           0 :         return "float2x2";
     327             :     }
     328           0 :     if (strcmp(floatTypeStr, "mat3") == 0)
     329             :     {
     330           0 :         return "float3x3";
     331             :     }
     332           0 :     if (strcmp(floatTypeStr, "mat4") == 0)
     333             :     {
     334           0 :         return "float4x4";
     335             :     }
     336           0 :     if (strcmp(floatTypeStr, "mat2x3") == 0)
     337             :     {
     338           0 :         return "float2x3";
     339             :     }
     340           0 :     if (strcmp(floatTypeStr, "mat2x4") == 0)
     341             :     {
     342           0 :         return "float2x4";
     343             :     }
     344           0 :     if (strcmp(floatTypeStr, "mat3x2") == 0)
     345             :     {
     346           0 :         return "float3x2";
     347             :     }
     348           0 :     if (strcmp(floatTypeStr, "mat3x4") == 0)
     349             :     {
     350           0 :         return "float3x4";
     351             :     }
     352           0 :     if (strcmp(floatTypeStr, "mat4x2") == 0)
     353             :     {
     354           0 :         return "float4x2";
     355             :     }
     356           0 :     if (strcmp(floatTypeStr, "mat4x3") == 0)
     357             :     {
     358           0 :         return "float4x3";
     359             :     }
     360           0 :     UNREACHABLE();
     361             :     return nullptr;
     362             : }
     363             : 
     364           0 : std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType)
     365             : {
     366           0 :     return GetHLSLTypeStr(glslType);
     367             : }
     368             : 
     369           0 : void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
     370             : {
     371             :     // In HLSL scalars are the same as 1-vectors.
     372           0 :     writeVectorRoundingHelpers(sink, 1);
     373           0 : }
     374             : 
     375           0 : void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
     376             :                                                           const unsigned int size)
     377             : {
     378           0 :     std::stringstream vecTypeStrStr;
     379           0 :     vecTypeStrStr << "float" << size;
     380           0 :     std::string vecType = vecTypeStrStr.str();
     381             : 
     382             :     // clang-format off
     383             :     sink <<
     384           0 :         vecType << " angle_frm(" << vecType << " v) {\n"
     385             :         "    v = clamp(v, -65504.0, 65504.0);\n"
     386           0 :         "    " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
     387           0 :         "    bool" << size << " isNonZero = exponent < -25.0;\n"
     388             :         "    v = v * exp2(-exponent);\n"
     389             :         "    v = sign(v) * floor(abs(v));\n"
     390           0 :         "    return v * exp2(exponent) * (float" << size << ")(isNonZero);\n"
     391           0 :         "}\n";
     392             : 
     393             :     sink <<
     394           0 :         vecType << " angle_frl(" << vecType << " v) {\n"
     395             :         "    v = clamp(v, -2.0, 2.0);\n"
     396             :         "    v = v * 256.0;\n"
     397             :         "    v = sign(v) * floor(abs(v));\n"
     398             :         "    return v * 0.00390625;\n"
     399           0 :         "}\n";
     400             :     // clang-format on
     401           0 : }
     402             : 
     403           0 : void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
     404             :                                                          const unsigned int columns,
     405             :                                                          const unsigned int rows,
     406             :                                                          const char *functionName)
     407             : {
     408           0 :     std::stringstream matTypeStrStr;
     409           0 :     matTypeStrStr << "float" << columns << "x" << rows;
     410           0 :     std::string matType = matTypeStrStr.str();
     411             : 
     412           0 :     sink << matType << " " << functionName << "(" << matType << " m) {\n"
     413           0 :          << "    " << matType << " rounded;\n";
     414             : 
     415           0 :     for (unsigned int i = 0; i < columns; ++i)
     416             :     {
     417           0 :         sink << "    rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
     418             :     }
     419             : 
     420             :     sink << "    return rounded;\n"
     421           0 :             "}\n";
     422           0 : }
     423             : 
     424           0 : bool canRoundFloat(const TType &type)
     425             : {
     426           0 :     return type.getBasicType() == EbtFloat && !type.isArray() &&
     427           0 :            (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
     428             : }
     429             : 
     430           0 : TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
     431             : {
     432           0 :     TIntermAggregate *callNode = new TIntermAggregate();
     433           0 :     callNode->setOp(EOpFunctionCall);
     434           0 :     TName nameObj(TFunction::mangleName(name));
     435           0 :     nameObj.setInternal(true);
     436           0 :     callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
     437           0 :     callNode->getSequence()->push_back(child);
     438           0 :     return callNode;
     439             : }
     440             : 
     441           0 : TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild)
     442             : {
     443           0 :     TString roundFunctionName;
     444           0 :     if (roundedChild->getPrecision() == EbpMedium)
     445           0 :         roundFunctionName = "angle_frm";
     446             :     else
     447           0 :         roundFunctionName = "angle_frl";
     448           0 :     TIntermAggregate *callNode = createInternalFunctionCallNode(roundFunctionName, roundedChild);
     449           0 :     callNode->setType(roundedChild->getType());
     450           0 :     return callNode;
     451             : }
     452             : 
     453           0 : TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr)
     454             : {
     455           0 :     std::stringstream strstr;
     456           0 :     if (left->getPrecision() == EbpMedium)
     457           0 :         strstr << "angle_compound_" << opNameStr << "_frm";
     458             :     else
     459           0 :         strstr << "angle_compound_" << opNameStr << "_frl";
     460           0 :     TString functionName = strstr.str().c_str();
     461           0 :     TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left);
     462           0 :     callNode->getSequence()->push_back(right);
     463           0 :     return callNode;
     464             : }
     465             : 
     466           0 : bool parentUsesResult(TIntermNode* parent, TIntermNode* node)
     467             : {
     468           0 :     if (!parent)
     469             :     {
     470           0 :         return false;
     471             :     }
     472             : 
     473           0 :     TIntermBlock *blockParent = parent->getAsBlock();
     474             :     // If the parent is a block, the result is not assigned anywhere,
     475             :     // so rounding it is not needed. In particular, this can avoid a lot of
     476             :     // unnecessary rounding of unused return values of assignment.
     477           0 :     if (blockParent)
     478             :     {
     479           0 :         return false;
     480             :     }
     481           0 :     TIntermBinary *binaryParent = parent->getAsBinaryNode();
     482           0 :     if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node))
     483             :     {
     484           0 :         return false;
     485             :     }
     486           0 :     return true;
     487             : }
     488             : 
     489             : }  // namespace anonymous
     490             : 
     491           0 : EmulatePrecision::EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion)
     492             :     : TLValueTrackingTraverser(true, true, true, symbolTable, shaderVersion),
     493           0 :       mDeclaringVariables(false)
     494           0 : {}
     495             : 
     496           0 : void EmulatePrecision::visitSymbol(TIntermSymbol *node)
     497             : {
     498           0 :     if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere())
     499             :     {
     500           0 :         TIntermNode *replacement = createRoundingFunctionCallNode(node);
     501           0 :         queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     502             :     }
     503           0 : }
     504             : 
     505             : 
     506           0 : bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node)
     507             : {
     508           0 :     bool visitChildren = true;
     509             : 
     510           0 :     TOperator op = node->getOp();
     511             : 
     512             :     // RHS of initialize is not being declared.
     513           0 :     if (op == EOpInitialize && visit == InVisit)
     514           0 :         mDeclaringVariables = false;
     515             : 
     516           0 :     if ((op == EOpIndexDirectStruct) && visit == InVisit)
     517           0 :         visitChildren = false;
     518             : 
     519           0 :     if (visit != PreVisit)
     520           0 :         return visitChildren;
     521             : 
     522           0 :     const TType& type = node->getType();
     523           0 :     bool roundFloat = canRoundFloat(type);
     524             : 
     525           0 :     if (roundFloat) {
     526           0 :         switch (op) {
     527             :           // Math operators that can result in a float may need to apply rounding to the return
     528             :           // value. Note that in the case of assignment, the rounding is applied to its return
     529             :           // value here, not the value being assigned.
     530             :           case EOpAssign:
     531             :           case EOpAdd:
     532             :           case EOpSub:
     533             :           case EOpMul:
     534             :           case EOpDiv:
     535             :           case EOpVectorTimesScalar:
     536             :           case EOpVectorTimesMatrix:
     537             :           case EOpMatrixTimesVector:
     538             :           case EOpMatrixTimesScalar:
     539             :           case EOpMatrixTimesMatrix:
     540             :           {
     541           0 :             TIntermNode *parent = getParentNode();
     542           0 :             if (!parentUsesResult(parent, node))
     543             :             {
     544           0 :                 break;
     545             :             }
     546           0 :             TIntermNode *replacement = createRoundingFunctionCallNode(node);
     547           0 :             queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     548           0 :             break;
     549             :           }
     550             : 
     551             :           // Compound assignment cases need to replace the operator with a function call.
     552             :           case EOpAddAssign:
     553             :           {
     554             :               mEmulateCompoundAdd.insert(
     555           0 :                   TypePair(type.getBuiltInTypeNameString(),
     556           0 :                            node->getRight()->getType().getBuiltInTypeNameString()));
     557           0 :               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
     558           0 :                   node->getLeft(), node->getRight(), "add");
     559           0 :               queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     560           0 :               break;
     561             :           }
     562             :           case EOpSubAssign:
     563             :           {
     564             :               mEmulateCompoundSub.insert(
     565           0 :                   TypePair(type.getBuiltInTypeNameString(),
     566           0 :                            node->getRight()->getType().getBuiltInTypeNameString()));
     567           0 :               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
     568           0 :                   node->getLeft(), node->getRight(), "sub");
     569           0 :               queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     570           0 :               break;
     571             :           }
     572             :           case EOpMulAssign:
     573             :           case EOpVectorTimesMatrixAssign:
     574             :           case EOpVectorTimesScalarAssign:
     575             :           case EOpMatrixTimesScalarAssign:
     576             :           case EOpMatrixTimesMatrixAssign:
     577             :           {
     578             :               mEmulateCompoundMul.insert(
     579           0 :                   TypePair(type.getBuiltInTypeNameString(),
     580           0 :                            node->getRight()->getType().getBuiltInTypeNameString()));
     581           0 :               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
     582           0 :                   node->getLeft(), node->getRight(), "mul");
     583           0 :               queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     584           0 :               break;
     585             :           }
     586             :           case EOpDivAssign:
     587             :           {
     588             :               mEmulateCompoundDiv.insert(
     589           0 :                   TypePair(type.getBuiltInTypeNameString(),
     590           0 :                            node->getRight()->getType().getBuiltInTypeNameString()));
     591           0 :               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
     592           0 :                   node->getLeft(), node->getRight(), "div");
     593           0 :               queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     594           0 :               break;
     595             :           }
     596             :           default:
     597             :             // The rest of the binary operations should not need precision emulation.
     598           0 :             break;
     599             :         }
     600             :     }
     601           0 :     return visitChildren;
     602             : }
     603             : 
     604           0 : bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node)
     605             : {
     606             :     // Variable or interface block declaration.
     607           0 :     if (visit == PreVisit)
     608             :     {
     609           0 :         mDeclaringVariables = true;
     610             :     }
     611           0 :     else if (visit == InVisit)
     612             :     {
     613           0 :         mDeclaringVariables = true;
     614             :     }
     615             :     else
     616             :     {
     617           0 :         mDeclaringVariables = false;
     618             :     }
     619           0 :     return true;
     620             : }
     621             : 
     622           0 : bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
     623             : {
     624           0 :     bool visitChildren = true;
     625           0 :     switch (node->getOp())
     626             :     {
     627             :       case EOpConstructStruct:
     628           0 :         break;
     629             :       case EOpPrototype:
     630           0 :         visitChildren = false;
     631           0 :         break;
     632             :       case EOpParameters:
     633           0 :         visitChildren = false;
     634           0 :         break;
     635             :       case EOpInvariantDeclaration:
     636           0 :         visitChildren = false;
     637           0 :         break;
     638             :       case EOpFunctionCall:
     639             :       {
     640             :         // Function call.
     641           0 :         if (visit == PreVisit)
     642             :         {
     643             :             // User-defined function return values are not rounded, this relies on that
     644             :             // calculations producing the value were rounded.
     645           0 :             TIntermNode *parent = getParentNode();
     646           0 :             if (canRoundFloat(node->getType()) && !isInFunctionMap(node) &&
     647           0 :                 parentUsesResult(parent, node))
     648             :             {
     649           0 :                 TIntermNode *replacement = createRoundingFunctionCallNode(node);
     650           0 :                 queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     651             :             }
     652             :         }
     653           0 :         break;
     654             :       }
     655             :       default:
     656           0 :         TIntermNode *parent = getParentNode();
     657           0 :         if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node))
     658             :         {
     659           0 :             TIntermNode *replacement = createRoundingFunctionCallNode(node);
     660           0 :             queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     661             :         }
     662           0 :         break;
     663             :     }
     664           0 :     return visitChildren;
     665             : }
     666             : 
     667           0 : bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
     668             : {
     669           0 :     switch (node->getOp())
     670             :     {
     671             :       case EOpNegative:
     672             :       case EOpVectorLogicalNot:
     673             :       case EOpLogicalNot:
     674             :       case EOpPostIncrement:
     675             :       case EOpPostDecrement:
     676             :       case EOpPreIncrement:
     677             :       case EOpPreDecrement:
     678           0 :         break;
     679             :       default:
     680           0 :         if (canRoundFloat(node->getType()) && visit == PreVisit)
     681             :         {
     682           0 :             TIntermNode *replacement = createRoundingFunctionCallNode(node);
     683           0 :             queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     684             :         }
     685           0 :         break;
     686             :     }
     687             : 
     688           0 :     return true;
     689             : }
     690             : 
     691           0 : void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink,
     692             :                                              const int shaderVersion,
     693             :                                              const ShShaderOutput outputLanguage)
     694             : {
     695             :     std::unique_ptr<RoundingHelperWriter> roundingHelperWriter(
     696           0 :         RoundingHelperWriter::createHelperWriter(outputLanguage));
     697             : 
     698           0 :     roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion);
     699             : 
     700           0 :     EmulationSet::const_iterator it;
     701           0 :     for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++)
     702           0 :         roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add");
     703           0 :     for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++)
     704           0 :         roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub");
     705           0 :     for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++)
     706           0 :         roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div");
     707           0 :     for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++)
     708           0 :         roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul");
     709           0 : }
     710             : 
     711             : // static
     712           0 : bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage)
     713             : {
     714           0 :     switch (outputLanguage)
     715             :     {
     716             :         case SH_HLSL_4_1_OUTPUT:
     717             :         case SH_ESSL_OUTPUT:
     718           0 :             return true;
     719             :         default:
     720             :             // Other languages not yet supported
     721           0 :             return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
     722           0 :                     sh::IsGLSL130OrNewer(outputLanguage));
     723             :     }
     724             : }
     725             : 
     726             : }  // namespace sh

Generated by: LCOV version 1.13