michael@0: From: Jeff Gilbert michael@0: Bug 771406 - Add emulation for GLSL faceforward() to ANGLE - r=bjacob michael@0: michael@0: diff --git a/gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp b/gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp michael@0: --- a/gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp michael@0: +++ b/gfx/angle/src/compiler/BuiltInFunctionEmulator.cpp michael@0: @@ -26,16 +26,22 @@ const char* kFunctionEmulationVertexSour michael@0: "#error no emulation for distance(vec3, vec3)", michael@0: "#error no emulation for distance(vec4, vec4)", michael@0: michael@0: "#define webgl_dot_emu(x, y) ((x) * (y))", michael@0: "#error no emulation for dot(vec2, vec2)", michael@0: "#error no emulation for dot(vec3, vec3)", michael@0: "#error no emulation for dot(vec4, vec4)", michael@0: michael@0: + // |faceforward(N, I, Nref)| is |dot(NRef, I) < 0 ? N : -N| michael@0: + "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))", michael@0: + "#error no emulation for faceforward(vec2, vec2, vec2)", michael@0: + "#error no emulation for faceforward(vec3, vec3, vec3)", michael@0: + "#error no emulation for faceforward(vec4, vec4, vec4)", michael@0: + michael@0: "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", michael@0: "#error no emulation for length(vec2)", michael@0: "#error no emulation for length(vec3)", michael@0: "#error no emulation for length(vec4)", michael@0: michael@0: "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", michael@0: "#error no emulation for normalize(vec2)", michael@0: "#error no emulation for normalize(vec3)", michael@0: @@ -58,16 +64,22 @@ const char* kFunctionEmulationFragmentSo michael@0: "#error no emulation for distance(vec3, vec3)", michael@0: "#error no emulation for distance(vec4, vec4)", michael@0: michael@0: "#define webgl_dot_emu(x, y) ((x) * (y))", michael@0: "#error no emulation for dot(vec2, vec2)", michael@0: "#error no emulation for dot(vec3, vec3)", michael@0: "#error no emulation for dot(vec4, vec4)", michael@0: michael@0: + // |faceforward(N, I, Nref)| is |dot(NRef, I) < 0 ? N : -N| michael@0: + "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))", michael@0: + "#error no emulation for faceforward(vec2, vec2, vec2)", michael@0: + "#error no emulation for faceforward(vec3, vec3, vec3)", michael@0: + "#error no emulation for faceforward(vec4, vec4, vec4)", michael@0: + michael@0: "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", michael@0: "#error no emulation for length(vec2)", michael@0: "#error no emulation for length(vec3)", michael@0: "#error no emulation for length(vec4)", michael@0: michael@0: "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", michael@0: "#error no emulation for normalize(vec2)", michael@0: "#error no emulation for normalize(vec3)", michael@0: @@ -89,16 +101,20 @@ const bool kFunctionEmulationVertexMask[ michael@0: true, // TFunctionDistance1_1 michael@0: false, // TFunctionDistance2_2 michael@0: false, // TFunctionDistance3_3 michael@0: false, // TFunctionDistance4_4 michael@0: true, // TFunctionDot1_1 michael@0: false, // TFunctionDot2_2 michael@0: false, // TFunctionDot3_3 michael@0: false, // TFunctionDot4_4 michael@0: + true, // TFunctionFaceForward1_1_1 michael@0: + false, // TFunctionFaceForward2_2_2 michael@0: + false, // TFunctionFaceForward3_3_3 michael@0: + false, // TFunctionFaceForward4_4_4 michael@0: true, // TFunctionLength1 michael@0: false, // TFunctionLength2 michael@0: false, // TFunctionLength3 michael@0: false, // TFunctionLength4 michael@0: true, // TFunctionNormalize1 michael@0: false, // TFunctionNormalize2 michael@0: false, // TFunctionNormalize3 michael@0: false, // TFunctionNormalize4 michael@0: @@ -115,16 +131,20 @@ const bool kFunctionEmulationVertexMask[ michael@0: false, // TFunctionDistance1_1 michael@0: false, // TFunctionDistance2_2 michael@0: false, // TFunctionDistance3_3 michael@0: false, // TFunctionDistance4_4 michael@0: false, // TFunctionDot1_1 michael@0: false, // TFunctionDot2_2 michael@0: false, // TFunctionDot3_3 michael@0: false, // TFunctionDot4_4 michael@0: + false, // TFunctionFaceForward1_1_1 michael@0: + false, // TFunctionFaceForward2_2_2 michael@0: + false, // TFunctionFaceForward3_3_3 michael@0: + false, // TFunctionFaceForward4_4_4 michael@0: false, // TFunctionLength1 michael@0: false, // TFunctionLength2 michael@0: false, // TFunctionLength3 michael@0: false, // TFunctionLength4 michael@0: false, // TFunctionNormalize1 michael@0: false, // TFunctionNormalize2 michael@0: false, // TFunctionNormalize3 michael@0: false, // TFunctionNormalize4 michael@0: @@ -146,16 +166,20 @@ const bool kFunctionEmulationFragmentMas michael@0: true, // TFunctionDistance1_1 michael@0: false, // TFunctionDistance2_2 michael@0: false, // TFunctionDistance3_3 michael@0: false, // TFunctionDistance4_4 michael@0: true, // TFunctionDot1_1 michael@0: false, // TFunctionDot2_2 michael@0: false, // TFunctionDot3_3 michael@0: false, // TFunctionDot4_4 michael@0: + true, // TFunctionFaceForward1_1_1 michael@0: + false, // TFunctionFaceForward2_2_2 michael@0: + false, // TFunctionFaceForward3_3_3 michael@0: + false, // TFunctionFaceForward4_4_4 michael@0: true, // TFunctionLength1 michael@0: false, // TFunctionLength2 michael@0: false, // TFunctionLength3 michael@0: false, // TFunctionLength4 michael@0: true, // TFunctionNormalize1 michael@0: false, // TFunctionNormalize2 michael@0: false, // TFunctionNormalize3 michael@0: false, // TFunctionNormalize4 michael@0: @@ -172,16 +196,20 @@ const bool kFunctionEmulationFragmentMas michael@0: false, // TFunctionDistance1_1 michael@0: false, // TFunctionDistance2_2 michael@0: false, // TFunctionDistance3_3 michael@0: false, // TFunctionDistance4_4 michael@0: false, // TFunctionDot1_1 michael@0: false, // TFunctionDot2_2 michael@0: false, // TFunctionDot3_3 michael@0: false, // TFunctionDot4_4 michael@0: + false, // TFunctionFaceForward1_1_1 michael@0: + false, // TFunctionFaceForward2_2_2 michael@0: + false, // TFunctionFaceForward3_3_3 michael@0: + false, // TFunctionFaceForward4_4_4 michael@0: false, // TFunctionLength1 michael@0: false, // TFunctionLength2 michael@0: false, // TFunctionLength3 michael@0: false, // TFunctionLength4 michael@0: false, // TFunctionNormalize1 michael@0: false, // TFunctionNormalize2 michael@0: false, // TFunctionNormalize3 michael@0: false, // TFunctionNormalize4 michael@0: @@ -239,25 +267,37 @@ public: michael@0: case EOpReflect: michael@0: case EOpRefract: michael@0: case EOpMul: michael@0: break; michael@0: default: michael@0: return true; michael@0: }; michael@0: const TIntermSequence& sequence = node->getSequence(); michael@0: - // Right now we only handle built-in functions with two parameters. michael@0: - if (sequence.size() != 2) michael@0: + bool needToEmulate = false; michael@0: + michael@0: + if (sequence.size() == 2) { michael@0: + TIntermTyped* param1 = sequence[0]->getAsTyped(); michael@0: + TIntermTyped* param2 = sequence[1]->getAsTyped(); michael@0: + if (!param1 || !param2) michael@0: + return true; michael@0: + needToEmulate = mEmulator.SetFunctionCalled( michael@0: + node->getOp(), param1->getType(), param2->getType()); michael@0: + } else if (sequence.size() == 3) { michael@0: + TIntermTyped* param1 = sequence[0]->getAsTyped(); michael@0: + TIntermTyped* param2 = sequence[1]->getAsTyped(); michael@0: + TIntermTyped* param3 = sequence[2]->getAsTyped(); michael@0: + if (!param1 || !param2 || !param3) michael@0: + return true; michael@0: + needToEmulate = mEmulator.SetFunctionCalled( michael@0: + node->getOp(), param1->getType(), param2->getType(), param3->getType()); michael@0: + } else { michael@0: return true; michael@0: - TIntermTyped* param1 = sequence[0]->getAsTyped(); michael@0: - TIntermTyped* param2 = sequence[1]->getAsTyped(); michael@0: - if (!param1 || !param2) michael@0: - return true; michael@0: - bool needToEmulate = mEmulator.SetFunctionCalled( michael@0: - node->getOp(), param1->getType(), param2->getType()); michael@0: + } michael@0: + michael@0: if (needToEmulate) michael@0: node->setUseEmulatedFunction(); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: private: michael@0: BuiltInFunctionEmulator& mEmulator; michael@0: @@ -286,16 +326,23 @@ bool BuiltInFunctionEmulator::SetFunctio michael@0: bool BuiltInFunctionEmulator::SetFunctionCalled( michael@0: TOperator op, const TType& param1, const TType& param2) michael@0: { michael@0: TBuiltInFunction function = IdentifyFunction(op, param1, param2); michael@0: return SetFunctionCalled(function); michael@0: } michael@0: michael@0: bool BuiltInFunctionEmulator::SetFunctionCalled( michael@0: + TOperator op, const TType& param1, const TType& param2, const TType& param3) michael@0: +{ michael@0: + TBuiltInFunction function = IdentifyFunction(op, param1, param2, param3); michael@0: + return SetFunctionCalled(function); michael@0: +} michael@0: + michael@0: +bool BuiltInFunctionEmulator::SetFunctionCalled( michael@0: BuiltInFunctionEmulator::TBuiltInFunction function) { michael@0: if (function == TFunctionUnknown || mFunctionMask[function] == false) michael@0: return false; michael@0: for (size_t i = 0; i < mFunctions.size(); ++i) { michael@0: if (mFunctions[i] == function) michael@0: return true; michael@0: } michael@0: mFunctions.push_back(function); michael@0: @@ -377,16 +424,44 @@ BuiltInFunctionEmulator::IdentifyFunctio michael@0: } michael@0: if (function == TFunctionUnknown) michael@0: return TFunctionUnknown; michael@0: if (param1.isVector()) michael@0: function += param1.getNominalSize() - 1; michael@0: return static_cast(function); michael@0: } michael@0: michael@0: +BuiltInFunctionEmulator::TBuiltInFunction michael@0: +BuiltInFunctionEmulator::IdentifyFunction( michael@0: + TOperator op, const TType& param1, const TType& param2, const TType& param3) michael@0: +{ michael@0: + // Check that all params have the same type, length, michael@0: + // and that they're not too large. michael@0: + if (param1.isVector() != param2.isVector() || michael@0: + param2.isVector() != param3.isVector() || michael@0: + param1.getNominalSize() != param2.getNominalSize() || michael@0: + param2.getNominalSize() != param3.getNominalSize() || michael@0: + param1.getNominalSize() > 4) michael@0: + return TFunctionUnknown; michael@0: + michael@0: + unsigned int function = TFunctionUnknown; michael@0: + switch (op) { michael@0: + case EOpFaceForward: michael@0: + function = TFunctionFaceForward1_1_1; michael@0: + break; michael@0: + default: michael@0: + break; michael@0: + } michael@0: + if (function == TFunctionUnknown) michael@0: + return TFunctionUnknown; michael@0: + if (param1.isVector()) michael@0: + function += param1.getNominalSize() - 1; michael@0: + return static_cast(function); michael@0: +} michael@0: + michael@0: void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( michael@0: TIntermNode* root) michael@0: { michael@0: ASSERT(root); michael@0: michael@0: BuiltInFunctionEmulationMarker marker(*this); michael@0: root->traverse(&marker); michael@0: } michael@0: diff --git a/gfx/angle/src/compiler/BuiltInFunctionEmulator.h b/gfx/angle/src/compiler/BuiltInFunctionEmulator.h michael@0: --- a/gfx/angle/src/compiler/BuiltInFunctionEmulator.h michael@0: +++ b/gfx/angle/src/compiler/BuiltInFunctionEmulator.h michael@0: @@ -23,16 +23,18 @@ public: michael@0: // Records that a function is called by the shader and might needs to be michael@0: // emulated. If the function's group is not in mFunctionGroupFilter, this michael@0: // becomes an no-op. michael@0: // Returns true if the function call needs to be replaced with an emulated michael@0: // one. michael@0: bool SetFunctionCalled(TOperator op, const TType& param); michael@0: bool SetFunctionCalled( michael@0: TOperator op, const TType& param1, const TType& param2); michael@0: + bool SetFunctionCalled( michael@0: + TOperator op, const TType& param1, const TType& param2, const TType& param3); michael@0: michael@0: // Output function emulation definition. This should be before any other michael@0: // shader source. michael@0: void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const; michael@0: michael@0: void MarkBuiltInFunctionsForEmulation(TIntermNode* root); michael@0: michael@0: void Cleanup(); michael@0: @@ -55,16 +57,21 @@ private: michael@0: TFunctionDistance3_3, // vec3 distance(vec3, vec3); michael@0: TFunctionDistance4_4, // vec4 distance(vec4, vec4); michael@0: michael@0: TFunctionDot1_1, // float dot(float, float); michael@0: TFunctionDot2_2, // vec2 dot(vec2, vec2); michael@0: TFunctionDot3_3, // vec3 dot(vec3, vec3); michael@0: TFunctionDot4_4, // vec4 dot(vec4, vec4); michael@0: michael@0: + TFunctionFaceForward1_1_1, // float faceforward(float, float, float); michael@0: + TFunctionFaceForward2_2_2, // vec2 faceforward(vec2, vec2, vec2); michael@0: + TFunctionFaceForward3_3_3, // vec3 faceforward(vec3, vec3, vec3); michael@0: + TFunctionFaceForward4_4_4, // vec4 faceforward(vec4, vec4, vec4); michael@0: + michael@0: TFunctionLength1, // float length(float); michael@0: TFunctionLength2, // float length(vec2); michael@0: TFunctionLength3, // float length(vec3); michael@0: TFunctionLength4, // float length(vec4); michael@0: michael@0: TFunctionNormalize1, // float normalize(float); michael@0: TFunctionNormalize2, // vec2 normalize(vec2); michael@0: TFunctionNormalize3, // vec3 normalize(vec3); michael@0: @@ -76,16 +83,18 @@ private: michael@0: TFunctionReflect4_4, // vec4 reflect(vec4, vec4); michael@0: michael@0: TFunctionUnknown michael@0: }; michael@0: michael@0: TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); michael@0: TBuiltInFunction IdentifyFunction( michael@0: TOperator op, const TType& param1, const TType& param2); michael@0: + TBuiltInFunction IdentifyFunction( michael@0: + TOperator op, const TType& param1, const TType& param2, const TType& param3); michael@0: michael@0: bool SetFunctionCalled(TBuiltInFunction function); michael@0: michael@0: std::vector mFunctions; michael@0: michael@0: const bool* mFunctionMask; // a boolean flag for each function. michael@0: const char** mFunctionSource; michael@0: };