Commit e17e3197 by Olli Etuaho

Use BuiltInFunctionEmulatorHLSL for all emulated functions

Implementation of missing built-in functions is a separate concern from outputting the intermediate tree itself as HLSL, so it makes sense to have all of the built-in emulation in a class that is separate from OutputHLSL. Being able to reuse the same logic for different emulated functions also makes the code more compact. Change-Id: Id503dc3a5c5e743ec65722add56d6ba216a03a7f Reviewed-on: https://chromium-review.googlesource.com/239872Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarNicolas Capens <capn@chromium.org> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 2aafa18b
...@@ -16,6 +16,133 @@ BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL() ...@@ -16,6 +16,133 @@ BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
TType float3(EbtFloat, 3); TType float3(EbtFloat, 3);
TType float4(EbtFloat, 4); TType float4(EbtFloat, 4);
AddEmulatedFunction(EOpMod, float1, float1,
"float webgl_mod_emu(float x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float2, float2,
"float2 webgl_mod_emu(float2 x, float2 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float2, float1,
"float2 webgl_mod_emu(float2 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float3, float3,
"float3 webgl_mod_emu(float3 x, float3 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float3, float1,
"float3 webgl_mod_emu(float3 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float4, float4,
"float4 webgl_mod_emu(float4 x, float4 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpMod, float4, float1,
"float4 webgl_mod_emu(float4 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
AddEmulatedFunction(EOpFaceForward, float1, float1, float1,
"float webgl_faceforward_emu(float N, float I, float Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n");
AddEmulatedFunction(EOpFaceForward, float2, float2, float2,
"float2 webgl_faceforward_emu(float2 N, float2 I, float2 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n");
AddEmulatedFunction(EOpFaceForward, float3, float3, float3,
"float3 webgl_faceforward_emu(float3 N, float3 I, float3 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n");
AddEmulatedFunction(EOpFaceForward, float4, float4, float4,
"float4 webgl_faceforward_emu(float4 N, float4 I, float4 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n");
AddEmulatedFunction(EOpAtan, float1, float1,
"float webgl_atan_emu(float y, float x)\n"
"{\n"
" if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
" return atan2(y, x);\n"
"}\n");
AddEmulatedFunction(EOpAtan, float2, float2,
"float2 webgl_atan_emu(float2 y, float2 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
"}\n");
AddEmulatedFunction(EOpAtan, float3, float3,
"float3 webgl_atan_emu(float3 y, float3 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
" return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
"}\n");
AddEmulatedFunction(EOpAtan, float4, float4,
"float4 webgl_atan_emu(float4 y, float4 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
" if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
" return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
"}\n");
AddEmulatedFunction(EOpAsinh, float1, AddEmulatedFunction(EOpAsinh, float1,
"float webgl_asinh_emu(in float x) {\n" "float webgl_asinh_emu(in float x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n" " return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
......
...@@ -112,21 +112,6 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) ...@@ -112,21 +112,6 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
mUsesPointSize = false; mUsesPointSize = false;
mUsesFragDepth = false; mUsesFragDepth = false;
mUsesXor = false; mUsesXor = false;
mUsesMod1 = false;
mUsesMod2v = false;
mUsesMod2f = false;
mUsesMod3v = false;
mUsesMod3f = false;
mUsesMod4v = false;
mUsesMod4f = false;
mUsesFaceforward1 = false;
mUsesFaceforward2 = false;
mUsesFaceforward3 = false;
mUsesFaceforward4 = false;
mUsesAtan2_1 = false;
mUsesAtan2_2 = false;
mUsesAtan2_3 = false;
mUsesAtan2_4 = false;
mUsesDiscardRewriting = false; mUsesDiscardRewriting = false;
mUsesNestedBreak = false; mUsesNestedBreak = false;
...@@ -188,14 +173,13 @@ void OutputHLSL::output() ...@@ -188,14 +173,13 @@ void OutputHLSL::output()
BuiltInFunctionEmulatorHLSL builtInFunctionEmulator; BuiltInFunctionEmulatorHLSL builtInFunctionEmulator;
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot);
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
header(); header(&builtInFunctionEmulator);
TInfoSinkBase& sink = mContext.infoSink().obj;
// Write emulated built-in functions if needed.
builtInFunctionEmulator.OutputEmulatedFunctionDefinition(sink, false);
builtInFunctionEmulator.Cleanup();
TInfoSinkBase& sink = mContext.infoSink().obj;
sink << mHeader.c_str(); sink << mHeader.c_str();
sink << mBody.c_str(); sink << mBody.c_str();
builtInFunctionEmulator.Cleanup();
} }
void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs) void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
...@@ -284,7 +268,7 @@ TString OutputHLSL::structInitializerString(int indent, const TStructure &struct ...@@ -284,7 +268,7 @@ TString OutputHLSL::structInitializerString(int indent, const TStructure &struct
return init; return init;
} }
void OutputHLSL::header() void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulator)
{ {
TInfoSinkBase &out = mHeader; TInfoSinkBase &out = mHeader;
...@@ -1219,174 +1203,7 @@ void OutputHLSL::header() ...@@ -1219,174 +1203,7 @@ void OutputHLSL::header()
"\n"; "\n";
} }
if (mUsesMod1) builtInFunctionEmulator->OutputEmulatedFunctionDefinition(out, false);
{
out << "float mod(float x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod2v)
{
out << "float2 mod(float2 x, float2 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod2f)
{
out << "float2 mod(float2 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod3v)
{
out << "float3 mod(float3 x, float3 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod3f)
{
out << "float3 mod(float3 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod4v)
{
out << "float4 mod(float4 x, float4 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesMod4f)
{
out << "float4 mod(float4 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n";
}
if (mUsesFaceforward1)
{
out << "float faceforward(float N, float I, float Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n";
}
if (mUsesFaceforward2)
{
out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n";
}
if (mUsesFaceforward3)
{
out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n";
}
if (mUsesFaceforward4)
{
out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
"{\n"
" if(dot(Nref, I) >= 0)\n"
" {\n"
" return -N;\n"
" }\n"
" else\n"
" {\n"
" return N;\n"
" }\n"
"}\n"
"\n";
}
if (mUsesAtan2_1)
{
out << "float atanyx(float y, float x)\n"
"{\n"
" if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
" return atan2(y, x);\n"
"}\n";
}
if (mUsesAtan2_2)
{
out << "float2 atanyx(float2 y, float2 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
"}\n";
}
if (mUsesAtan2_3)
{
out << "float3 atanyx(float3 y, float3 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
" return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
"}\n";
}
if (mUsesAtan2_4)
{
out << "float4 atanyx(float4 y, float4 x)\n"
"{\n"
" if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
" if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
" if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
" if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
" return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
"}\n";
}
} }
void OutputHLSL::visitSymbol(TIntermSymbol *node) void OutputHLSL::visitSymbol(TIntermSymbol *node)
...@@ -2262,37 +2079,14 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2262,37 +2079,14 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
case EOpMod: case EOpMod:
{ ASSERT(node->getUseEmulatedFunction());
// We need to look at the number of components in both arguments writeEmulatedFunctionTriplet(visit, "mod(");
const int modValue = (*node->getSequence())[0]->getAsTyped()->getNominalSize() * 10 +
(*node->getSequence())[1]->getAsTyped()->getNominalSize();
switch (modValue)
{
case 11: mUsesMod1 = true; break;
case 22: mUsesMod2v = true; break;
case 21: mUsesMod2f = true; break;
case 33: mUsesMod3v = true; break;
case 31: mUsesMod3f = true; break;
case 44: mUsesMod4v = true; break;
case 41: mUsesMod4f = true; break;
default: UNREACHABLE();
}
outputTriplet(visit, "mod(", ", ", ")");
}
break; break;
case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
case EOpAtan: case EOpAtan:
ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) ASSERT(node->getUseEmulatedFunction());
{ writeEmulatedFunctionTriplet(visit, "atan(");
case 1: mUsesAtan2_1 = true; break;
case 2: mUsesAtan2_2 = true; break;
case 3: mUsesAtan2_3 = true; break;
case 4: mUsesAtan2_4 = true; break;
default: UNREACHABLE();
}
outputTriplet(visit, "atanyx(", ", ", ")");
break; break;
case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
...@@ -2304,18 +2098,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2304,18 +2098,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
case EOpFaceForward: case EOpFaceForward:
{ ASSERT(node->getUseEmulatedFunction());
switch ((*node->getSequence())[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument writeEmulatedFunctionTriplet(visit, "faceforward(");
{
case 1: mUsesFaceforward1 = true; break;
case 2: mUsesFaceforward2 = true; break;
case 3: mUsesFaceforward3 = true; break;
case 4: mUsesFaceforward4 = true; break;
default: UNREACHABLE();
}
outputTriplet(visit, "faceforward(", ", ", ")");
}
break; break;
case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/ParseContext.h" #include "compiler/translator/ParseContext.h"
class BuiltInFunctionEmulatorHLSL;
namespace sh namespace sh
{ {
class UnfoldShortCircuit; class UnfoldShortCircuit;
...@@ -39,7 +41,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -39,7 +41,7 @@ class OutputHLSL : public TIntermTraverser
static TString initializer(const TType &type); static TString initializer(const TType &type);
protected: protected:
void header(); void header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulator);
// Visit AST nodes and output their code to the body stream // Visit AST nodes and output their code to the body stream
void visitSymbol(TIntermSymbol*); void visitSymbol(TIntermSymbol*);
...@@ -122,21 +124,6 @@ class OutputHLSL : public TIntermTraverser ...@@ -122,21 +124,6 @@ class OutputHLSL : public TIntermTraverser
bool mUsesPointSize; bool mUsesPointSize;
bool mUsesFragDepth; bool mUsesFragDepth;
bool mUsesXor; bool mUsesXor;
bool mUsesMod1;
bool mUsesMod2v;
bool mUsesMod2f;
bool mUsesMod3v;
bool mUsesMod3f;
bool mUsesMod4v;
bool mUsesMod4f;
bool mUsesFaceforward1;
bool mUsesFaceforward2;
bool mUsesFaceforward3;
bool mUsesFaceforward4;
bool mUsesAtan2_1;
bool mUsesAtan2_2;
bool mUsesAtan2_3;
bool mUsesAtan2_4;
bool mUsesDiscardRewriting; bool mUsesDiscardRewriting;
bool mUsesNestedBreak; bool mUsesNestedBreak;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment