LCOV - app.info - gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp

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-07-07 | 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