gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial