LCOV - code coverage report
Current view: directory - gfx/angle/src/compiler - BuiltInFunctionEmulator.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 110 0 0.0 %
Date: 2012-06-02 Functions: 13 0 0.0 %

       1                 : //
       2                 : // Copyright (c) 2002-2011 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/BuiltInFunctionEmulator.h"
       8                 : 
       9                 : #include "compiler/SymbolTable.h"
      10                 : 
      11                 : namespace {
      12                 : 
      13                 : // we use macros here instead of function definitions to work around more GLSL
      14                 : // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
      15                 : // problematic because if the argument has side-effects they will be repeatedly
      16                 : // evaluated. This is unlikely to show up in real shaders, but is something to
      17                 : // consider.
      18                 : const char* kFunctionEmulationVertexSource[] = {
      19                 :     "#error no emulation for atan(float, float)",
      20                 :     "vec2 webgl_atan_emu(vec2 y, vec2 x) { return vec2(atan(y[0], x[0]), atan(y[1], x[1])); }",
      21                 :     "vec3 webgl_atan_emu(vec3 y, vec3 x) { return vec3(atan(y[0], x[0]), atan(y[1], x[1]), atan(y[2], x[2])); }",
      22                 :     "vec4 webgl_atan_emu(vec4 y, vec4 x) { return vec4(atan(y[0], x[0]), atan(y[1], x[1]), atan(y[2], x[2]), atan(y[3], x[3])); }",
      23                 : 
      24                 :     "#error no emulation for cos(float)",
      25                 :     "#error no emulation for cos(vec2)",
      26                 :     "#error no emulation for cos(vec3)",
      27                 :     "#error no emulation for cos(vec4)",
      28                 : 
      29                 :     "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
      30                 :     "#error no emulation for distance(vec2, vec2)",
      31                 :     "#error no emulation for distance(vec3, vec3)",
      32                 :     "#error no emulation for distance(vec4, vec4)",
      33                 : 
      34                 :     "#define webgl_dot_emu(x, y) ((x) * (y))",
      35                 :     "#error no emulation for dot(vec2, vec2)",
      36                 :     "#error no emulation for dot(vec3, vec3)",
      37                 :     "#error no emulation for dot(vec4, vec4)",
      38                 : 
      39                 :     "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
      40                 :     "#error no emulation for length(vec2)",
      41                 :     "#error no emulation for length(vec3)",
      42                 :     "#error no emulation for length(vec4)",
      43                 : 
      44                 :     "#error no emulation for mod(float, float)",
      45                 :     "vec2 webgl_mod_emu(vec2 x, vec2 y) { return vec2(mod(x[0], y[0]), mod(x[1], y[1])); }",
      46                 :     "vec3 webgl_mod_emu(vec3 x, vec3 y) { return vec3(mod(x[0], y[0]), mod(x[1], y[1]), mod(x[2], y[2])); }",
      47                 :     "vec4 webgl_mod_emu(vec4 x, vec4 y) { return vec4(mod(x[0], y[0]), mod(x[1], y[1]), mod(x[2], y[2]), mod(x[3], y[3])); }",
      48                 : 
      49                 :     "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
      50                 :     "#error no emulation for normalize(vec2)",
      51                 :     "#error no emulation for normalize(vec3)",
      52                 :     "#error no emulation for normalize(vec4)",
      53                 : 
      54                 :     "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
      55                 :     "#error no emulation for reflect(vec2, vec2)",
      56                 :     "#error no emulation for reflect(vec3, vec3)",
      57                 :     "#error no emulation for reflect(vec4, vec4)"
      58                 : };
      59                 : 
      60                 : const char* kFunctionEmulationFragmentSource[] = {
      61                 :     "#error no emulation for atan(float, float)",
      62                 :     "#error no emulation for atan(vec2, vec2)",
      63                 :     "#error no emulation for atan(vec3, vec3)",
      64                 :     "#error no emulation for atan(vec4, vec4)",
      65                 : 
      66                 :     "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
      67                 :     "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
      68                 :     "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
      69                 :     "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
      70                 : 
      71                 :     "#error no emulation for distance(float, float)",
      72                 :     "#error no emulation for distance(vec2, vec2)",
      73                 :     "#error no emulation for distance(vec3, vec3)",
      74                 :     "#error no emulation for distance(vec4, vec4)",
      75                 : 
      76                 :     "#error no emulation for dot(float, float)",
      77                 :     "#error no emulation for dot(vec2, vec2)",
      78                 :     "#error no emulation for dot(vec3, vec3)",
      79                 :     "#error no emulation for dot(vec4, vec4)",
      80                 : 
      81                 :     "#error no emulation for length(float)",
      82                 :     "#error no emulation for length(vec2)",
      83                 :     "#error no emulation for length(vec3)",
      84                 :     "#error no emulation for length(vec4)",
      85                 : 
      86                 :     "#error no emulation for mod(float, float)",
      87                 :     "#error no emulation for mod(vec2, vec2)",
      88                 :     "#error no emulation for mod(vec3, vec3)",
      89                 :     "#error no emulation for mod(vec4, vec4)",
      90                 : 
      91                 :     "#error no emulation for normalize(float)",
      92                 :     "#error no emulation for normalize(vec2)",
      93                 :     "#error no emulation for normalize(vec3)",
      94                 :     "#error no emulation for normalize(vec4)",
      95                 : 
      96                 :     "#error no emulation for reflect(float, float)",
      97                 :     "#error no emulation for reflect(vec2, vec2)",
      98                 :     "#error no emulation for reflect(vec3, vec3)",
      99                 :     "#error no emulation for reflect(vec4, vec4)"
     100                 : };
     101                 : 
     102                 : const bool kFunctionEmulationVertexMask[] = {
     103                 : #if defined(__APPLE__)
     104                 :     // Work around ATI driver bugs in Mac.
     105                 :     false, // TFunctionAtan1_1
     106                 :     false, // TFunctionAtan2_2
     107                 :     false, // TFunctionAtan3_3
     108                 :     false, // TFunctionAtan4_4
     109                 :     false, // TFunctionCos1
     110                 :     false, // TFunctionCos2
     111                 :     false, // TFunctionCos3
     112                 :     false, // TFunctionCos4
     113                 :     true,  // TFunctionDistance1_1
     114                 :     false, // TFunctionDistance2_2
     115                 :     false, // TFunctionDistance3_3
     116                 :     false, // TFunctionDistance4_4
     117                 :     true,  // TFunctionDot1_1
     118                 :     false, // TFunctionDot2_2
     119                 :     false, // TFunctionDot3_3
     120                 :     false, // TFunctionDot4_4
     121                 :     true,  // TFunctionLength1
     122                 :     false, // TFunctionLength2
     123                 :     false, // TFunctionLength3
     124                 :     false, // TFunctionLength4
     125                 :     false, // TFunctionMod1_1
     126                 :     false, // TFunctionMod2_2
     127                 :     false, // TFunctionMod3_3
     128                 :     false, // TFunctionMod4_4
     129                 :     true,  // TFunctionNormalize1
     130                 :     false, // TFunctionNormalize2
     131                 :     false, // TFunctionNormalize3
     132                 :     false, // TFunctionNormalize4
     133                 :     true,  // TFunctionReflect1_1
     134                 :     false, // TFunctionReflect2_2
     135                 :     false, // TFunctionReflect3_3
     136                 :     false, // TFunctionReflect4_4
     137                 : #else
     138                 :     // Work around D3D driver bug in Win.
     139                 :     false, // TFunctionAtan1_1
     140                 :     true,  // TFunctionAtan2_2
     141                 :     true,  // TFunctionAtan3_3
     142                 :     true,  // TFunctionAtan4_4
     143                 :     false, // TFunctionCos1
     144                 :     false, // TFunctionCos2
     145                 :     false, // TFunctionCos3
     146                 :     false, // TFunctionCos4
     147                 :     false, // TFunctionDistance1_1
     148                 :     false, // TFunctionDistance2_2
     149                 :     false, // TFunctionDistance3_3
     150                 :     false, // TFunctionDistance4_4
     151                 :     false, // TFunctionDot1_1
     152                 :     false, // TFunctionDot2_2
     153                 :     false, // TFunctionDot3_3
     154                 :     false, // TFunctionDot4_4
     155                 :     false, // TFunctionLength1
     156                 :     false, // TFunctionLength2
     157                 :     false, // TFunctionLength3
     158                 :     false, // TFunctionLength4
     159                 :     false, // TFunctionMod1_1
     160                 :     true,  // TFunctionMod2_2
     161                 :     true,  // TFunctionMod3_3
     162                 :     true,  // TFunctionMod4_4
     163                 :     false, // TFunctionNormalize1
     164                 :     false, // TFunctionNormalize2
     165                 :     false, // TFunctionNormalize3
     166                 :     false, // TFunctionNormalize4
     167                 :     false, // TFunctionReflect1_1
     168                 :     false, // TFunctionReflect2_2
     169                 :     false, // TFunctionReflect3_3
     170                 :     false, // TFunctionReflect4_4
     171                 : #endif
     172                 :     false  // TFunctionUnknown
     173                 : };
     174                 : 
     175                 : const bool kFunctionEmulationFragmentMask[] = {
     176                 :     false, // TFunctionAtan1_1
     177                 :     false, // TFunctionAtan2_2
     178                 :     false, // TFunctionAtan3_3
     179                 :     false, // TFunctionAtan4_4
     180                 : #if defined(__APPLE__)
     181                 :     // Work around a ATI driver bug in Mac that causes crashes.
     182                 :     true,  // TFunctionCos1
     183                 :     true,  // TFunctionCos2
     184                 :     true,  // TFunctionCos3
     185                 :     true,  // TFunctionCos4
     186                 : #else
     187                 :     false, // TFunctionCos1
     188                 :     false, // TFunctionCos2
     189                 :     false, // TFunctionCos3
     190                 :     false, // TFunctionCos4
     191                 : #endif
     192                 :     false, // TFunctionDistance1_1
     193                 :     false, // TFunctionDistance2_2
     194                 :     false, // TFunctionDistance3_3
     195                 :     false, // TFunctionDistance4_4
     196                 :     false, // TFunctionDot1_1
     197                 :     false, // TFunctionDot2_2
     198                 :     false, // TFunctionDot3_3
     199                 :     false, // TFunctionDot4_4
     200                 :     false, // TFunctionLength1
     201                 :     false, // TFunctionLength2
     202                 :     false, // TFunctionLength3
     203                 :     false, // TFunctionLength4
     204                 :     false, // TFunctionMod1_1
     205                 :     false, // TFunctionMod2_2
     206                 :     false, // TFunctionMod3_3
     207                 :     false, // TFunctionMod4_4
     208                 :     false, // TFunctionNormalize1
     209                 :     false, // TFunctionNormalize2
     210                 :     false, // TFunctionNormalize3
     211                 :     false, // TFunctionNormalize4
     212                 :     false, // TFunctionReflect1_1
     213                 :     false, // TFunctionReflect2_2
     214                 :     false, // TFunctionReflect3_3
     215                 :     false, // TFunctionReflect4_4
     216                 :     false  // TFunctionUnknown
     217                 : };
     218                 : 
     219                 : class BuiltInFunctionEmulationMarker : public TIntermTraverser {
     220                 : public:
     221               0 :     BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
     222               0 :         : mEmulator(emulator)
     223                 :     {
     224               0 :     }
     225                 : 
     226               0 :     virtual bool visitUnary(Visit visit, TIntermUnary* node)
     227                 :     {
     228               0 :         if (visit == PreVisit) {
     229                 :             bool needToEmulate = mEmulator.SetFunctionCalled(
     230               0 :                 node->getOp(), node->getOperand()->getType());
     231               0 :             if (needToEmulate)
     232               0 :                 node->setUseEmulatedFunction();
     233                 :         }
     234               0 :         return true;
     235                 :     }
     236                 : 
     237               0 :     virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
     238                 :     {
     239               0 :         if (visit == PreVisit) {
     240                 :             // Here we handle all the built-in functions instead of the ones we
     241                 :             // currently identified as problematic.
     242               0 :             switch (node->getOp()) {
     243                 :                 case EOpLessThan:
     244                 :                 case EOpGreaterThan:
     245                 :                 case EOpLessThanEqual:
     246                 :                 case EOpGreaterThanEqual:
     247                 :                 case EOpVectorEqual:
     248                 :                 case EOpVectorNotEqual:
     249                 :                 case EOpMod:
     250                 :                 case EOpPow:
     251                 :                 case EOpAtan:
     252                 :                 case EOpMin:
     253                 :                 case EOpMax:
     254                 :                 case EOpClamp:
     255                 :                 case EOpMix:
     256                 :                 case EOpStep:
     257                 :                 case EOpSmoothStep:
     258                 :                 case EOpDistance:
     259                 :                 case EOpDot:
     260                 :                 case EOpCross:
     261                 :                 case EOpFaceForward:
     262                 :                 case EOpReflect:
     263                 :                 case EOpRefract:
     264                 :                 case EOpMul:
     265                 :                     break;
     266                 :                 default:
     267               0 :                     return true;
     268                 :             };
     269               0 :             const TIntermSequence& sequence = node->getSequence();
     270                 :             // Right now we only handle built-in functions with two parameters.
     271               0 :             if (sequence.size() != 2)
     272               0 :                 return true;
     273               0 :             TIntermTyped* param1 = sequence[0]->getAsTyped();
     274               0 :             TIntermTyped* param2 = sequence[1]->getAsTyped();
     275               0 :             if (!param1 || !param2)
     276               0 :                 return true;
     277                 :             bool needToEmulate = mEmulator.SetFunctionCalled(
     278               0 :                 node->getOp(), param1->getType(), param2->getType());
     279               0 :             if (needToEmulate)
     280               0 :                 node->setUseEmulatedFunction();
     281                 :         }
     282               0 :         return true;
     283                 :     }
     284                 : 
     285                 : private:
     286                 :     BuiltInFunctionEmulator& mEmulator;
     287                 : };
     288                 : 
     289                 : }  // anonymous namepsace
     290                 : 
     291               0 : BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
     292                 : {
     293               0 :     if (shaderType == SH_FRAGMENT_SHADER) {
     294               0 :         mFunctionMask = kFunctionEmulationFragmentMask;
     295               0 :         mFunctionSource = kFunctionEmulationFragmentSource;
     296                 :     } else {
     297               0 :         mFunctionMask = kFunctionEmulationVertexMask;
     298               0 :         mFunctionSource = kFunctionEmulationVertexSource;
     299                 :     }
     300               0 : }
     301                 : 
     302               0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
     303                 :     TOperator op, const TType& param)
     304                 : {
     305               0 :     TBuiltInFunction function = IdentifyFunction(op, param);
     306               0 :     return SetFunctionCalled(function);
     307                 : }
     308                 : 
     309               0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
     310                 :     TOperator op, const TType& param1, const TType& param2)
     311                 : {
     312               0 :     TBuiltInFunction function = IdentifyFunction(op, param1, param2);
     313               0 :     return SetFunctionCalled(function);
     314                 : }
     315                 : 
     316               0 : bool BuiltInFunctionEmulator::SetFunctionCalled(
     317                 :     BuiltInFunctionEmulator::TBuiltInFunction function) {
     318               0 :     if (function == TFunctionUnknown || mFunctionMask[function] == false)
     319               0 :         return false;
     320               0 :     for (size_t i = 0; i < mFunctions.size(); ++i) {
     321               0 :         if (mFunctions[i] == function)
     322               0 :             return true;
     323                 :     }
     324               0 :     mFunctions.push_back(function);
     325               0 :     return true;
     326                 : }
     327                 : 
     328               0 : void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
     329                 :     TInfoSinkBase& out, bool withPrecision) const
     330                 : {
     331               0 :     if (mFunctions.size() == 0)
     332               0 :         return;
     333               0 :     out << "// BEGIN: Generated code for built-in function emulation\n\n";
     334               0 :     if (withPrecision) {
     335               0 :         out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
     336               0 :             << "#define webgl_emu_precision highp\n"
     337               0 :             << "#else\n"
     338               0 :             << "#define webgl_emu_precision mediump\n"
     339               0 :             << "#endif\n\n";
     340                 :     } else {
     341               0 :         out << "#define webgl_emu_precision\n\n";
     342                 :     }
     343               0 :     for (size_t i = 0; i < mFunctions.size(); ++i) {
     344               0 :         out << mFunctionSource[mFunctions[i]] << "\n\n";
     345                 :     }
     346               0 :     out << "// END: Generated code for built-in function emulation\n\n";
     347                 : }
     348                 : 
     349                 : BuiltInFunctionEmulator::TBuiltInFunction
     350               0 : BuiltInFunctionEmulator::IdentifyFunction(
     351                 :     TOperator op, const TType& param)
     352                 : {
     353               0 :     if (param.getNominalSize() > 4)
     354               0 :         return TFunctionUnknown;
     355               0 :     unsigned int function = TFunctionUnknown;
     356               0 :     switch (op) {
     357                 :         case EOpCos:
     358               0 :             function = TFunctionCos1;
     359               0 :             break;
     360                 :         case EOpLength:
     361               0 :             function = TFunctionLength1;
     362               0 :             break;
     363                 :         case EOpNormalize:
     364               0 :             function = TFunctionNormalize1;
     365               0 :             break;
     366                 :         default:
     367               0 :             break;
     368                 :     }
     369               0 :     if (function == TFunctionUnknown)
     370               0 :         return TFunctionUnknown;
     371               0 :     if (param.isVector())
     372               0 :         function += param.getNominalSize() - 1;
     373               0 :     return static_cast<TBuiltInFunction>(function);
     374                 : }
     375                 : 
     376                 : BuiltInFunctionEmulator::TBuiltInFunction
     377               0 : BuiltInFunctionEmulator::IdentifyFunction(
     378                 :     TOperator op, const TType& param1, const TType& param2)
     379                 : {
     380                 :     // Right now for all the emulated functions with two parameters, the two
     381                 :     // parameters have the same type.
     382               0 :     if (param1.isVector() != param2.isVector() ||
     383               0 :         param1.getNominalSize() != param2.getNominalSize() ||
     384               0 :         param1.getNominalSize() > 4)
     385               0 :         return TFunctionUnknown;
     386                 : 
     387               0 :     unsigned int function = TFunctionUnknown;
     388               0 :     switch (op) {
     389                 :         case EOpAtan:
     390               0 :             function = TFunctionAtan1_1;
     391               0 :             break;
     392                 :         case EOpDistance:
     393               0 :             function = TFunctionDistance1_1;
     394               0 :             break;
     395                 :         case EOpDot:
     396               0 :             function = TFunctionDot1_1;
     397               0 :             break;
     398                 :         case EOpMod:
     399               0 :             function = TFunctionMod1_1;
     400               0 :             break;
     401                 :         case EOpReflect:
     402               0 :             function = TFunctionReflect1_1;
     403               0 :             break;
     404                 :         default:
     405               0 :             break;
     406                 :     }
     407               0 :     if (function == TFunctionUnknown)
     408               0 :         return TFunctionUnknown;
     409               0 :     if (param1.isVector())
     410               0 :         function += param1.getNominalSize() - 1;
     411               0 :     return static_cast<TBuiltInFunction>(function);
     412                 : }
     413                 : 
     414               0 : void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
     415                 :     TIntermNode* root)
     416                 : {
     417               0 :     ASSERT(root);
     418                 : 
     419               0 :     BuiltInFunctionEmulationMarker marker(*this);
     420               0 :     root->traverse(&marker);
     421               0 : }
     422                 : 
     423               0 : void BuiltInFunctionEmulator::Cleanup()
     424                 : {
     425               0 :     mFunctions.clear();
     426               0 : }
     427                 : 
     428                 : //static
     429               0 : TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
     430                 :     const TString& name)
     431                 : {
     432               0 :     ASSERT(name[name.length() - 1] == '(');
     433               0 :     return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
     434                 : }
     435                 : 

Generated by: LCOV version 1.7