Commit 35bcad42 by Jamie Madill Committed by Commit Bot

Optimize builtin function emulator class.

This refactor uses a generator to produce static arrays instead of using a bunch of std::map inserting statements. It speeds up shader translation because every shader compile would create and tear down this table. Currently it is implemented as a flat array, but in the future we could use compile-time hashing to implement faster lookup. BUG=chromium:697758 Change-Id: I689f7de4d9b2c8c76095bb313f4c040116fc61d2 Reviewed-on: https://chromium-review.googlesource.com/521226 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent a71a98ee
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
'compiler/translator/NodeSearch.h', 'compiler/translator/NodeSearch.h',
'compiler/translator/Operator.cpp', 'compiler/translator/Operator.cpp',
'compiler/translator/Operator.h', 'compiler/translator/Operator.h',
'compiler/translator/ParamType.h',
'compiler/translator/ParseContext.cpp', 'compiler/translator/ParseContext.cpp',
'compiler/translator/ParseContext.h', 'compiler/translator/ParseContext.h',
'compiler/translator/PoolAlloc.cpp', 'compiler/translator/PoolAlloc.cpp',
...@@ -215,6 +216,7 @@ ...@@ -215,6 +216,7 @@
'compiler/translator/UniformHLSL.h', 'compiler/translator/UniformHLSL.h',
'compiler/translator/UtilsHLSL.cpp', 'compiler/translator/UtilsHLSL.cpp',
'compiler/translator/UtilsHLSL.h', 'compiler/translator/UtilsHLSL.h',
'compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp',
], ],
'angle_translator_lib_vulkan_sources': 'angle_translator_lib_vulkan_sources':
[ [
......
...@@ -95,29 +95,27 @@ BuiltInFunctionEmulator::BuiltInFunctionEmulator() ...@@ -95,29 +95,27 @@ BuiltInFunctionEmulator::BuiltInFunctionEmulator()
{ {
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction( FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
TOperator op, const TType *param,
const TType *param, const char *emulatedFunctionDefinition)
const char *emulatedFunctionDefinition)
{ {
FunctionId id(op, param); FunctionId id(op, param);
mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
return id; return id;
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction( FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
TOperator op, const TType *param1,
const TType *param1, const TType *param2,
const TType *param2, const char *emulatedFunctionDefinition)
const char *emulatedFunctionDefinition)
{ {
FunctionId id(op, param1, param2); FunctionId id(op, param1, param2);
mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
return id; return id;
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
FunctionId dependency, const FunctionId &dependency,
TOperator op, TOperator op,
const TType *param1, const TType *param1,
const TType *param2, const TType *param2,
...@@ -129,33 +127,31 @@ BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction ...@@ -129,33 +127,31 @@ BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction
return id; return id;
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction( FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
TOperator op, const TType *param1,
const TType *param1, const TType *param2,
const TType *param2, const TType *param3,
const TType *param3, const char *emulatedFunctionDefinition)
const char *emulatedFunctionDefinition)
{ {
FunctionId id(op, param1, param2, param3); FunctionId id(op, param1, param2, param3);
mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
return id; return id;
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction( FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
TOperator op, const TType *param1,
const TType *param1, const TType *param2,
const TType *param2, const TType *param3,
const TType *param3, const TType *param4,
const TType *param4, const char *emulatedFunctionDefinition)
const char *emulatedFunctionDefinition)
{ {
FunctionId id(op, param1, param2, param3, param4); FunctionId id(op, param1, param2, param3, param4);
mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
return id; return id;
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
FunctionId dependency, const FunctionId &dependency,
TOperator op, TOperator op,
const TType *param1, const TType *param1,
const TType *param2, const TType *param2,
...@@ -176,9 +172,12 @@ bool BuiltInFunctionEmulator::isOutputEmpty() const ...@@ -176,9 +172,12 @@ bool BuiltInFunctionEmulator::isOutputEmpty() const
void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
{ {
for (size_t i = 0; i < mFunctions.size(); ++i) for (const auto &function : mFunctions)
{ {
out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n"; const char *body = findEmulatedFunction(function);
ASSERT(body);
out << body;
out << "\n\n";
} }
} }
...@@ -211,34 +210,55 @@ bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, ...@@ -211,34 +210,55 @@ bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
return setFunctionCalled(FunctionId(op, &param1, &param2, &param3, &param4)); return setFunctionCalled(FunctionId(op, &param1, &param2, &param3, &param4));
} }
bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId) const char *BuiltInFunctionEmulator::findEmulatedFunction(const FunctionId &functionId) const
{ {
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end()) for (const auto &queryFunction : mQueryFunctions)
{ {
for (size_t i = 0; i < mFunctions.size(); ++i) const char *result = queryFunction(functionId);
{ if (result)
if (mFunctions[i] == functionId)
return true;
}
// If the function depends on another, mark the dependency as called.
auto dependency = mFunctionDependencies.find(functionId);
if (dependency != mFunctionDependencies.end())
{ {
setFunctionCalled((*dependency).second); return result;
} }
// Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
// remain valid and constant.
mFunctions.push_back(functionId.getCopy());
return true;
} }
return false;
const auto &result = mEmulatedFunctions.find(functionId);
if (result != mEmulatedFunctions.end())
{
return result->second.c_str();
}
return nullptr;
}
bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId)
{
if (!findEmulatedFunction(functionId))
{
return false;
}
for (size_t i = 0; i < mFunctions.size(); ++i)
{
if (mFunctions[i] == functionId)
return true;
}
// If the function depends on another, mark the dependency as called.
auto dependency = mFunctionDependencies.find(functionId);
if (dependency != mFunctionDependencies.end())
{
setFunctionCalled((*dependency).second);
}
// Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
// remain valid and constant.
mFunctions.push_back(functionId.getCopy());
return true;
} }
void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root) void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
{ {
ASSERT(root); ASSERT(root);
if (mEmulatedFunctions.empty()) if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
return; return;
BuiltInFunctionEmulationMarker marker(*this); BuiltInFunctionEmulationMarker marker(*this);
...@@ -251,6 +271,11 @@ void BuiltInFunctionEmulator::cleanup() ...@@ -251,6 +271,11 @@ void BuiltInFunctionEmulator::cleanup()
mFunctionDependencies.clear(); mFunctionDependencies.clear();
} }
void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
{
mQueryFunctions.push_back(queryFunc);
}
// static // static
void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name) void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
{ {
...@@ -258,7 +283,7 @@ void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, cons ...@@ -258,7 +283,7 @@ void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, cons
out << "webgl_" << name << "_emu"; out << "webgl_" << name << "_emu";
} }
BuiltInFunctionEmulator::FunctionId::FunctionId() FunctionId::FunctionId()
: mOp(EOpNull), : mOp(EOpNull),
mParam1(TCache::getType(EbtVoid)), mParam1(TCache::getType(EbtVoid)),
mParam2(TCache::getType(EbtVoid)), mParam2(TCache::getType(EbtVoid)),
...@@ -267,7 +292,7 @@ BuiltInFunctionEmulator::FunctionId::FunctionId() ...@@ -267,7 +292,7 @@ BuiltInFunctionEmulator::FunctionId::FunctionId()
{ {
} }
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param) FunctionId::FunctionId(TOperator op, const TType *param)
: mOp(op), : mOp(op),
mParam1(param), mParam1(param),
mParam2(TCache::getType(EbtVoid)), mParam2(TCache::getType(EbtVoid)),
...@@ -276,9 +301,7 @@ BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param ...@@ -276,9 +301,7 @@ BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param
{ {
} }
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
const TType *param1,
const TType *param2)
: mOp(op), : mOp(op),
mParam1(param1), mParam1(param1),
mParam2(param2), mParam2(param2),
...@@ -287,32 +310,27 @@ BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, ...@@ -287,32 +310,27 @@ BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
{ {
} }
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3)
const TType *param1,
const TType *param2,
const TType *param3)
: mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(TCache::getType(EbtVoid)) : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(TCache::getType(EbtVoid))
{ {
} }
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, FunctionId::FunctionId(TOperator op,
const TType *param1, const TType *param1,
const TType *param2, const TType *param2,
const TType *param3, const TType *param3,
const TType *param4) const TType *param4)
: mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(param4) : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(param4)
{ {
} }
bool BuiltInFunctionEmulator::FunctionId::operator==( bool FunctionId::operator==(const FunctionId &other) const
const BuiltInFunctionEmulator::FunctionId &other) const
{ {
return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 && return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 &&
*mParam3 == *other.mParam3 && *mParam4 == *other.mParam4); *mParam3 == *other.mParam3 && *mParam4 == *other.mParam4);
} }
bool BuiltInFunctionEmulator::FunctionId::operator<( bool FunctionId::operator<(const FunctionId &other) const
const BuiltInFunctionEmulator::FunctionId &other) const
{ {
if (mOp != other.mOp) if (mOp != other.mOp)
return mOp < other.mOp; return mOp < other.mOp;
...@@ -327,7 +345,7 @@ bool BuiltInFunctionEmulator::FunctionId::operator<( ...@@ -327,7 +345,7 @@ bool BuiltInFunctionEmulator::FunctionId::operator<(
return false; // all fields are equal return false; // all fields are equal
} }
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const FunctionId FunctionId::getCopy() const
{ {
return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3), return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3),
new TType(*mParam4)); new TType(*mParam4));
......
...@@ -9,10 +9,82 @@ ...@@ -9,10 +9,82 @@
#include "compiler/translator/InfoSink.h" #include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/ParamType.h"
namespace sh namespace sh
{ {
struct MiniFunctionId
{
constexpr MiniFunctionId(TOperator op = EOpNull,
ParamType paramType1 = ParamType::Void,
ParamType paramType2 = ParamType::Void,
ParamType paramType3 = ParamType::Void,
ParamType paramType4 = ParamType::Void)
: op(op),
paramType1(paramType1),
paramType2(paramType2),
paramType3(paramType3),
paramType4(paramType4)
{
}
TOperator op;
ParamType paramType1;
ParamType paramType2;
ParamType paramType3;
ParamType paramType4;
};
class FunctionId final
{
public:
FunctionId();
FunctionId(TOperator op, const TType *param);
FunctionId(TOperator op, const TType *param1, const TType *param2);
FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3);
FunctionId(TOperator op,
const TType *param1,
const TType *param2,
const TType *param3,
const TType *param4);
FunctionId(const FunctionId &) = default;
FunctionId &operator=(const FunctionId &) = default;
bool operator==(const FunctionId &other) const;
bool operator<(const FunctionId &other) const;
FunctionId getCopy() const;
private:
friend bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId);
TOperator mOp;
// The memory that these TType objects use is freed by PoolAllocator. The
// BuiltInFunctionEmulator's lifetime can extend until after the memory pool is freed, but
// that's not an issue since this class never destructs these objects.
const TType *mParam1;
const TType *mParam2;
const TType *mParam3;
const TType *mParam4;
};
inline bool operator==(ParamType paramType, const TType *type)
{
return SameParamType(paramType, type->getBasicType(), type->getNominalSize(),
type->getSecondarySize());
}
inline bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId)
{
return miniId.op == functionId.mOp && miniId.paramType1 == functionId.mParam1 &&
miniId.paramType2 == functionId.mParam2 && miniId.paramType3 == functionId.mParam3 &&
miniId.paramType4 == functionId.mParam4;
}
using BuiltinQueryFunc = const char *(const FunctionId &);
// //
// This class decides which built-in functions need to be replaced with the emulated ones. It can be // This class decides which built-in functions need to be replaced with the emulated ones. It can be
// used to work around driver bugs or implement functions that are not natively implemented on a // used to work around driver bugs or implement functions that are not natively implemented on a
...@@ -35,39 +107,6 @@ class BuiltInFunctionEmulator ...@@ -35,39 +107,6 @@ class BuiltInFunctionEmulator
// Output function emulation definition. This should be before any other shader source. // Output function emulation definition. This should be before any other shader source.
void outputEmulatedFunctions(TInfoSinkBase &out) const; void outputEmulatedFunctions(TInfoSinkBase &out) const;
class FunctionId
{
public:
FunctionId();
FunctionId(TOperator op, const TType *param);
FunctionId(TOperator op, const TType *param1, const TType *param2);
FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3);
FunctionId(TOperator op,
const TType *param1,
const TType *param2,
const TType *param3,
const TType *param4);
FunctionId(const FunctionId &) = default;
FunctionId &operator=(const FunctionId &) = default;
bool operator==(const FunctionId &other) const;
bool operator<(const FunctionId &other) const;
FunctionId getCopy() const;
private:
TOperator mOp;
// The memory that these TType objects use is freed by PoolAllocator. The
// BuiltInFunctionEmulator's lifetime can extend until after the memory pool is freed, but
// that's not an issue since this class never destructs these objects.
const TType *mParam1;
const TType *mParam2;
const TType *mParam3;
const TType *mParam4;
};
// Add functions that need to be emulated. // Add functions that need to be emulated.
FunctionId addEmulatedFunction(TOperator op, FunctionId addEmulatedFunction(TOperator op,
const TType *param, const TType *param,
...@@ -88,12 +127,12 @@ class BuiltInFunctionEmulator ...@@ -88,12 +127,12 @@ class BuiltInFunctionEmulator
const TType *param4, const TType *param4,
const char *emulatedFunctionDefinition); const char *emulatedFunctionDefinition);
FunctionId addEmulatedFunctionWithDependency(FunctionId dependency, FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency,
TOperator op, TOperator op,
const TType *param1, const TType *param1,
const TType *param2, const TType *param2,
const char *emulatedFunctionDefinition); const char *emulatedFunctionDefinition);
FunctionId addEmulatedFunctionWithDependency(FunctionId dependency, FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency,
TOperator op, TOperator op,
const TType *param1, const TType *param1,
const TType *param2, const TType *param2,
...@@ -101,6 +140,8 @@ class BuiltInFunctionEmulator ...@@ -101,6 +140,8 @@ class BuiltInFunctionEmulator
const TType *param4, const TType *param4,
const char *emulatedFunctionDefinition); const char *emulatedFunctionDefinition);
void addFunctionMap(BuiltinQueryFunc queryFunc);
private: private:
class BuiltInFunctionEmulationMarker; class BuiltInFunctionEmulationMarker;
...@@ -121,6 +162,8 @@ class BuiltInFunctionEmulator ...@@ -121,6 +162,8 @@ class BuiltInFunctionEmulator
bool setFunctionCalled(const FunctionId &functionId); bool setFunctionCalled(const FunctionId &functionId);
const char *findEmulatedFunction(const FunctionId &functionId) const;
// Map from function id to emulated function definition // Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions; std::map<FunctionId, std::string> mEmulatedFunctions;
...@@ -130,6 +173,9 @@ class BuiltInFunctionEmulator ...@@ -130,6 +173,9 @@ class BuiltInFunctionEmulator
// Called function ids // Called function ids
std::vector<FunctionId> mFunctions; std::vector<FunctionId> mFunctions;
// Constexpr function tables.
std::vector<BuiltinQueryFunc *> mQueryFunctions;
}; };
} // namespace sh } // namespace sh
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
namespace sh namespace sh
{ {
// Defined in emulated_builtin_functions_hlsl_autogen.cpp.
const char *FindHLSLFunction(const FunctionId &functionID);
void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion) int targetGLSLVersion)
{ {
...@@ -70,10 +73,6 @@ void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator ...@@ -70,10 +73,6 @@ void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
{ {
TType *float1 = new TType(EbtFloat);
TType *float2 = new TType(EbtFloat, 2);
TType *float3 = new TType(EbtFloat, 3);
TType *float4 = new TType(EbtFloat, 4);
TType *int1 = new TType(EbtInt); TType *int1 = new TType(EbtInt);
TType *int2 = new TType(EbtInt, 2); TType *int2 = new TType(EbtInt, 2);
TType *int3 = new TType(EbtInt, 3); TType *int3 = new TType(EbtInt, 3);
...@@ -83,874 +82,12 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) ...@@ -83,874 +82,12 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
TType *uint3 = new TType(EbtUInt, 3); TType *uint3 = new TType(EbtUInt, 3);
TType *uint4 = new TType(EbtUInt, 4); TType *uint4 = new TType(EbtUInt, 4);
emu->addEmulatedFunction(EOpMod, float1, float1, emu->addFunctionMap(FindHLSLFunction);
"float webgl_mod_emu(float x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float2, float2,
"float2 webgl_mod_emu(float2 x, float2 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float2, float1,
"float2 webgl_mod_emu(float2 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float3, float3,
"float3 webgl_mod_emu(float3 x, float3 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float3, float1,
"float3 webgl_mod_emu(float3 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float4, float4,
"float4 webgl_mod_emu(float4 x, float4 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpMod, float4, float1,
"float4 webgl_mod_emu(float4 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpFrexp, float1, int1,
"float webgl_frexp_emu(float x, out int exp)\n"
"{\n"
" float fexp;\n"
" float mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int(fexp);\n"
" return mantissa;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpFrexp, float2, int2,
"float2 webgl_frexp_emu(float2 x, out int2 exp)\n"
"{\n"
" float2 fexp;\n"
" float2 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int2(fexp);\n"
" return mantissa;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpFrexp, float3, int3,
"float3 webgl_frexp_emu(float3 x, out int3 exp)\n"
"{\n"
" float3 fexp;\n"
" float3 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int3(fexp);\n"
" return mantissa;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpFrexp, float4, int4,
"float4 webgl_frexp_emu(float4 x, out int4 exp)\n"
"{\n"
" float4 fexp;\n"
" float4 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int4(fexp);\n"
" return mantissa;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpLdexp, float1, int1,
"float webgl_ldexp_emu(float x, int exp)\n"
"{\n"
" return ldexp(x, float(exp));\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpLdexp, float2, int2,
"float2 webgl_ldexp_emu(float2 x, int2 exp)\n"
"{\n"
" return ldexp(x, float2(exp));\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpLdexp, float3, int3,
"float3 webgl_ldexp_emu(float3 x, int3 exp)\n"
"{\n"
" return ldexp(x, float3(exp));\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpLdexp, float4, int4,
"float4 webgl_ldexp_emu(float4 x, int4 exp)\n"
"{\n"
" return ldexp(x, float4(exp));\n"
"}\n"
"\n");
emu->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");
emu->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");
emu->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");
emu->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");
emu->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");
emu->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");
emu->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");
emu->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");
emu->addEmulatedFunction(EOpAsinh, float1,
"float webgl_asinh_emu(in float x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAsinh, float2,
"float2 webgl_asinh_emu(in float2 x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAsinh, float3,
"float3 webgl_asinh_emu(in float3 x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAsinh, float4,
"float4 webgl_asinh_emu(in float4 x) {\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAcosh, float1,
"float webgl_acosh_emu(in float x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAcosh, float2,
"float2 webgl_acosh_emu(in float2 x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAcosh, float3,
"float3 webgl_acosh_emu(in float3 x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAcosh, float4,
"float4 webgl_acosh_emu(in float4 x) {\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n");
emu->addEmulatedFunction(EOpAtanh, float1,
"float webgl_atanh_emu(in float x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
emu->addEmulatedFunction(EOpAtanh, float2,
"float2 webgl_atanh_emu(in float2 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
emu->addEmulatedFunction(EOpAtanh, float3,
"float3 webgl_atanh_emu(in float3 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
emu->addEmulatedFunction(EOpAtanh, float4,
"float4 webgl_atanh_emu(in float4 x) {\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n");
emu->addEmulatedFunction(
EOpRoundEven, float1,
"float webgl_roundEven_emu(in float x) {\n"
" return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
"}\n");
emu->addEmulatedFunction(
EOpRoundEven, float2,
"float2 webgl_roundEven_emu(in float2 x) {\n"
" float2 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" return v;\n"
"}\n");
emu->addEmulatedFunction(
EOpRoundEven, float3,
"float3 webgl_roundEven_emu(in float3 x) {\n"
" float3 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
" return v;\n"
"}\n");
emu->addEmulatedFunction(
EOpRoundEven, float4,
"float4 webgl_roundEven_emu(in float4 x) {\n"
" float4 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
" v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n"
" return v;\n"
"}\n");
emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
"int webgl_toSnorm16(in float x) {\n"
" return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
"}\n"
"\n"
"uint webgl_packSnorm2x16_emu(in float2 v) {\n"
" int x = webgl_toSnorm16(v.x);\n"
" int y = webgl_toSnorm16(v.y);\n"
" return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
"}\n");
emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
"uint webgl_toUnorm16(in float x) {\n"
" return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
"}\n"
"\n"
"uint webgl_packUnorm2x16_emu(in float2 v) {\n"
" uint x = webgl_toUnorm16(v.x);\n"
" uint y = webgl_toUnorm16(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpPackHalf2x16, float2,
"uint webgl_packHalf2x16_emu(in float2 v) {\n"
" uint x = f32tof16(v.x);\n"
" uint y = f32tof16(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm16(in uint x) {\n"
" int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
"}\n"
"\n"
"float2 webgl_unpackSnorm2x16_emu(in uint u) {\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
" return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
"float webgl_fromUnorm16(in uint x) {\n"
" return float(x) / 65535.0;\n"
"}\n"
"\n"
"float2 webgl_unpackUnorm2x16_emu(in uint u) {\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
"float2 webgl_unpackHalf2x16_emu(in uint u) {\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return float2(f16tof32(x), f16tof32(y));\n"
"}\n");
emu->addEmulatedFunction(EOpPackSnorm4x8, float4,
"int webgl_toSnorm8(in float x) {\n"
" return int(round(clamp(x, -1.0, 1.0) * 127.0));\n"
"}\n"
"\n"
"uint webgl_packSnorm4x8_emu(in float4 v) {\n"
" int x = webgl_toSnorm8(v.x);\n"
" int y = webgl_toSnorm8(v.y);\n"
" int z = webgl_toSnorm8(v.z);\n"
" int w = webgl_toSnorm8(v.w);\n"
" return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) "
"| ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n"
"}\n");
emu->addEmulatedFunction(EOpPackUnorm4x8, float4,
"uint webgl_toUnorm8(in float x) {\n"
" return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n"
"}\n"
"\n"
"uint webgl_packUnorm4x8_emu(in float4 v) {\n"
" uint x = webgl_toUnorm8(v.x);\n"
" uint y = webgl_toUnorm8(v.y);\n"
" uint z = webgl_toUnorm8(v.z);\n"
" uint w = webgl_toUnorm8(v.w);\n"
" return (w << 24) | (z << 16) | (y << 8) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm4x8, uint1,
"float webgl_fromSnorm8(in uint x) {\n"
" int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n"
" return clamp(float(xi) / 127.0, -1.0, 1.0);\n"
"}\n"
"\n"
"float4 webgl_unpackSnorm4x8_emu(in uint u) {\n"
" uint w = (u >> 24);\n"
" uint z = (u >> 16);\n"
" uint y = (u >> 8);\n"
" uint x = u;\n"
" return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), "
"webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackUnorm4x8, uint1,
"float webgl_fromUnorm8(in uint x) {\n"
" return float(x) / 255.0;\n"
"}\n"
"\n"
"float4 webgl_unpackUnorm4x8_emu(in uint u) {\n"
" uint w = (u >> 24) & 0xffu;\n"
" uint z = (u >> 16) & 0xffu;\n"
" uint y = (u >> 8) & 0xffu;\n"
" uint x = u & 0xffu;\n"
" return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), "
"webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n"
"}\n");
// The matrix resulting from outer product needs to be transposed
// (matrices are stored as transposed to simplify element access in HLSL).
// So the function should return transpose(c * r) where c is a column vector
// and r is a row vector. This can be simplified by using the following
// formula:
// transpose(c * r) = transpose(r) * transpose(c)
// transpose(r) and transpose(c) are in a sense free, since to get the
// transpose of r, we simply can build a column matrix out of the original
// vector instead of a row matrix.
emu->addEmulatedFunction(EOpOuterProduct, float2, float2,
"float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n"
" return mul(float2x1(r), float1x2(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float3, float3,
"float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n"
" return mul(float3x1(r), float1x3(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float4, float4,
"float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n"
" return mul(float4x1(r), float1x4(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float3, float2,
"float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n"
" return mul(float2x1(r), float1x3(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float2, float3,
"float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n"
" return mul(float3x1(r), float1x2(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float4, float2,
"float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n"
" return mul(float2x1(r), float1x4(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float2, float4,
"float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n"
" return mul(float4x1(r), float1x2(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float4, float3,
"float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n"
" return mul(float3x1(r), float1x4(c));\n"
"}\n");
emu->addEmulatedFunction(EOpOuterProduct, float3, float4,
"float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n"
" return mul(float4x1(r), float1x3(c));\n"
"}\n");
TType *mat2 = new TType(EbtFloat, 2, 2);
TType *mat3 = new TType(EbtFloat, 3, 3);
TType *mat4 = new TType(EbtFloat, 4, 4);
// Remember here that the parameter matrix is actually the transpose
// of the matrix that we're trying to invert, and the resulting matrix
// should also be the transpose of the inverse.
// When accessing the parameter matrix with m[a][b] it can be thought of so
// that a is the column and b is the row of the matrix that we're inverting.
// We calculate the inverse as the adjugate matrix divided by the
// determinant of the matrix being inverted. However, as the result needs
// to be transposed, we actually use of the transpose of the adjugate matrix
// which happens to be the cofactor matrix. That's stored in "cof".
// We don't need to care about divide-by-zero since results are undefined
// for singular or poorly-conditioned matrices.
emu->addEmulatedFunction(EOpInverse, mat2,
"float2x2 webgl_inverse_emu(in float2x2 m) {\n"
" float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n"
" return cof / determinant(transpose(m));\n"
"}\n");
// cofAB is the cofactor for column A and row B.
emu->addEmulatedFunction(
EOpInverse, mat3,
"float3x3 webgl_inverse_emu(in float3x3 m) {\n"
" float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n"
" float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n"
" float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n"
" float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n"
" float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n"
" float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n"
" float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n"
" float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n"
" float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n"
" float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n"
" return cof / determinant(transpose(m));\n"
"}\n");
emu->addEmulatedFunction(
EOpInverse, mat4,
"float4x4 webgl_inverse_emu(in float4x4 m) {\n"
" float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * "
"m[1][2] * m[2][3]"
" - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * "
"m[1][3];\n"
" float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * "
"m[1][2] * m[2][3]"
" - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * "
"m[1][3]);\n"
" float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * "
"m[1][1] * m[2][3]"
" - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * "
"m[1][3];\n"
" float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * "
"m[1][1] * m[2][2]"
" - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * "
"m[1][2]);\n"
" float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * "
"m[0][2] * m[2][3]"
" - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * "
"m[0][3]);\n"
" float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * "
"m[0][2] * m[2][3]"
" - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * "
"m[0][3];\n"
" float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * "
"m[0][1] * m[2][3]"
" - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * "
"m[0][3]);\n"
" float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * "
"m[0][1] * m[2][2]"
" - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * "
"m[0][2];\n"
" float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * "
"m[0][2] * m[1][3]"
" - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * "
"m[0][3];\n"
" float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * "
"m[0][2] * m[1][3]"
" - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * "
"m[0][3]);\n"
" float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * "
"m[0][1] * m[1][3]"
" - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * "
"m[0][3];\n"
" float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * "
"m[0][1] * m[1][2]"
" - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * "
"m[0][2]);\n"
" float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * "
"m[0][2] * m[1][3]"
" - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * "
"m[0][3]);\n"
" float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * "
"m[0][2] * m[1][3]"
" - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * "
"m[0][3];\n"
" float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * "
"m[0][1] * m[1][3]"
" - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * "
"m[0][3]);\n"
" float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * "
"m[0][1] * m[1][2]"
" - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * "
"m[0][2];\n"
" float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,"
" cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n"
" return cof / determinant(transpose(m));\n"
"}\n");
TType *bool1 = new TType(EbtBool);
TType *bool2 = new TType(EbtBool, 2);
TType *bool3 = new TType(EbtBool, 3);
TType *bool4 = new TType(EbtBool, 4);
// Emulate ESSL3 variant of mix that takes last argument as boolean vector.
// genType mix (genType x, genType y, genBType a): Selects which vector each returned component
// comes from.
// For a component of 'a' that is false, the corresponding component of 'x' is returned.For a
// component of 'a' that is true,
// the corresponding component of 'y' is returned.
emu->addEmulatedFunction(EOpMix, float1, float1, bool1,
"float webgl_mix_emu(float x, float y, bool a)\n"
"{\n"
" return a ? y : x;\n"
"}\n");
emu->addEmulatedFunction(EOpMix, float2, float2, bool2,
"float2 webgl_mix_emu(float2 x, float2 y, bool2 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n");
emu->addEmulatedFunction(EOpMix, float3, float3, bool3,
"float3 webgl_mix_emu(float3 x, float3 y, bool3 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n");
emu->addEmulatedFunction(EOpMix, float4, float4, bool4,
"float4 webgl_mix_emu(float4 x, float4 y, bool4 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, uint1, int1, int1,
"uint webgl_bitfieldExtract_emu(uint value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return 0u;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, uint2, int1, int1,
"uint2 webgl_bitfieldExtract_emu(uint2 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint2(0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, uint3, int1, int1,
"uint3 webgl_bitfieldExtract_emu(uint3 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint3(0u, 0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, uint4, int1, int1,
"uint4 webgl_bitfieldExtract_emu(uint4 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint4(0u, 0u, 0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, int1, int1, int1,
"int webgl_bitfieldExtract_emu(int value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return 0;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32 && (resultUnsigned & maskMsb) != 0)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, int2, int1, int1,
"int2 webgl_bitfieldExtract_emu(int2 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int2(0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint2 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, int3, int1, int1,
"int3 webgl_bitfieldExtract_emu(int3 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int3(0, 0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint3 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldExtract, int4, int1, int1,
"int4 webgl_bitfieldExtract_emu(int4 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int4(0, 0, 0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint4 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, uint1, uint1, int1, int1,
"uint webgl_bitfieldInsert_emu(uint base, uint insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, uint2, uint2, int1, int1,
"uint2 webgl_bitfieldInsert_emu(uint2 base, uint2 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, uint3, uint3, int1, int1,
"uint3 webgl_bitfieldInsert_emu(uint3 base, uint3 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, uint4, uint4, int1, int1,
"uint4 webgl_bitfieldInsert_emu(uint4 base, uint4 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, int1, int1, int1, int1,
"int webgl_bitfieldInsert_emu(int base, int insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & "
"insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, int2, int2, int1, int1,
"int2 webgl_bitfieldInsert_emu(int2 base, int2 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & "
"insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, int3, int3, int1, int1,
"int3 webgl_bitfieldInsert_emu(int3 base, int3 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & "
"insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(
EOpBitfieldInsert, int4, int4, int1, int1,
"int4 webgl_bitfieldInsert_emu(int4 base, int4 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & "
"insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n");
emu->addEmulatedFunction(EOpUaddCarry, uint1, uint1, uint1,
"uint webgl_uaddCarry_emu(uint x, uint y, out uint carry)\n"
"{\n"
" carry = uint(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n");
emu->addEmulatedFunction(EOpUaddCarry, uint2, uint2, uint2,
"uint2 webgl_uaddCarry_emu(uint2 x, uint2 y, out uint2 carry)\n"
"{\n"
" carry = uint2(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n");
emu->addEmulatedFunction(EOpUaddCarry, uint3, uint3, uint3,
"uint3 webgl_uaddCarry_emu(uint3 x, uint3 y, out uint3 carry)\n"
"{\n"
" carry = uint3(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n");
emu->addEmulatedFunction(EOpUaddCarry, uint4, uint4, uint4,
"uint4 webgl_uaddCarry_emu(uint4 x, uint4 y, out uint4 carry)\n"
"{\n"
" carry = uint4(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n");
emu->addEmulatedFunction(EOpUsubBorrow, uint1, uint1, uint1,
"uint webgl_usubBorrow_emu(uint x, uint y, out uint borrow)\n"
"{\n"
" borrow = uint(x < y);\n"
" return x - y;\n"
"}\n");
emu->addEmulatedFunction(EOpUsubBorrow, uint2, uint2, uint2,
"uint2 webgl_usubBorrow_emu(uint2 x, uint2 y, out uint2 borrow)\n"
"{\n"
" borrow = uint2(x < y);\n"
" return x - y;\n"
"}\n");
emu->addEmulatedFunction(EOpUsubBorrow, uint3, uint3, uint3,
"uint3 webgl_usubBorrow_emu(uint3 x, uint3 y, out uint3 borrow)\n"
"{\n"
" borrow = uint3(x < y);\n"
" return x - y;\n"
"}\n");
emu->addEmulatedFunction(EOpUsubBorrow, uint4, uint4, uint4,
"uint4 webgl_usubBorrow_emu(uint4 x, uint4 y, out uint4 borrow)\n"
"{\n"
" borrow = uint4(x < y);\n"
" return x - y;\n"
"}\n");
// (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32 // (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32
// Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because: // Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because:
// a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000 // a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000
BuiltInFunctionEmulator::FunctionId umulExtendedUint1 = emu->addEmulatedFunction( FunctionId umulExtendedUint1 = emu->addEmulatedFunction(
EOpUmulExtended, uint1, uint1, uint1, uint1, EOpUmulExtended, uint1, uint1, uint1, uint1,
"void webgl_umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n" "void webgl_umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n"
"{\n" "{\n"
...@@ -993,7 +130,7 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) ...@@ -993,7 +130,7 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
// result needs to be negative. // result needs to be negative.
// TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is // TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is
// -2^31. abs(-2^31) is undefined. // -2^31. abs(-2^31) is undefined.
BuiltInFunctionEmulator::FunctionId imulExtendedInt1 = emu->addEmulatedFunctionWithDependency( FunctionId imulExtendedInt1 = emu->addEmulatedFunctionWithDependency(
umulExtendedUint1, EOpImulExtended, int1, int1, int1, int1, umulExtendedUint1, EOpImulExtended, int1, int1, int1, int1,
"void webgl_imulExtended_emu(int x, int y, out int msb, out int lsb)\n" "void webgl_imulExtended_emu(int x, int y, out int msb, out int lsb)\n"
"{\n" "{\n"
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ParamType:
// Helper type for built-in function emulator tables. Defines types for parameters.
#ifndef COMPILER_TRANSLATOR_PARAMTYPE_H_
#define COMPILER_TRANSLATOR_PARAMTYPE_H_
#include "common/angleutils.h"
#include "compiler/translator/BaseTypes.h"
namespace sh
{
enum class ParamType : uint8_t
{
Void,
Bool1,
Bool2,
Bool3,
Bool4,
Float1,
Float2,
Float3,
Float4,
Int1,
Int2,
Int3,
Int4,
Mat2,
Mat3,
Mat4,
Uint1,
Uint2,
Uint3,
Uint4,
Last,
};
struct ParamTypeInfo
{
ParamType self;
TBasicType basicType;
int primarySize;
int secondarySize;
};
constexpr ParamTypeInfo g_ParamTypeInfo[] = {
{ParamType::Void, EbtVoid, 1, 1}, {ParamType::Bool1, EbtBool, 1, 1},
{ParamType::Bool2, EbtBool, 2, 1}, {ParamType::Bool3, EbtBool, 3, 1},
{ParamType::Bool4, EbtBool, 4, 1}, {ParamType::Float1, EbtFloat, 1, 1},
{ParamType::Float2, EbtFloat, 2, 1}, {ParamType::Float3, EbtFloat, 3, 1},
{ParamType::Float4, EbtFloat, 4, 1}, {ParamType::Int1, EbtInt, 1, 1},
{ParamType::Int2, EbtInt, 2, 1}, {ParamType::Int3, EbtInt, 3, 1},
{ParamType::Int4, EbtInt, 4, 1}, {ParamType::Mat2, EbtFloat, 2, 2},
{ParamType::Mat3, EbtFloat, 3, 3}, {ParamType::Mat4, EbtFloat, 4, 4},
{ParamType::Uint1, EbtUInt, 1, 1}, {ParamType::Uint2, EbtUInt, 2, 1},
{ParamType::Uint3, EbtUInt, 3, 1}, {ParamType::Uint4, EbtUInt, 4, 1},
};
constexpr size_t ParamTypeIndex(ParamType paramType)
{
return static_cast<size_t>(paramType);
}
constexpr size_t NumParamTypes()
{
return ParamTypeIndex(ParamType::Last);
}
static_assert(ArraySize(g_ParamTypeInfo) == NumParamTypes(), "Invalid array size");
constexpr TBasicType GetBasicType(ParamType paramType)
{
return g_ParamTypeInfo[ParamTypeIndex(paramType)].basicType;
}
constexpr int GetPrimarySize(ParamType paramType)
{
return g_ParamTypeInfo[ParamTypeIndex(paramType)].primarySize;
}
constexpr int GetSecondarySize(ParamType paramType)
{
return g_ParamTypeInfo[ParamTypeIndex(paramType)].secondarySize;
}
constexpr bool SameParamType(ParamType paramType,
TBasicType basicType,
int primarySize,
int secondarySize)
{
return GetBasicType(paramType) == basicType && primarySize == GetPrimarySize(paramType) &&
secondarySize == GetSecondarySize(paramType);
}
} // namespace sh
#endif // COMPILER_TRANSLATOR_PARAMTYPE_H_
[
{
"op":"mod",
"return_type":"float",
"args":[
"float x",
"float y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float2",
"args":[
"float2 x",
"float2 y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float2",
"args":[
"float2 x",
"float y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float3",
"args":[
"float3 x",
"float3 y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float3",
"args":[
"float3 x",
"float y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float4",
"args":[
"float4 x",
"float4 y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"mod",
"return_type":"float4",
"args":[
"float4 x",
"float y"
],
"body":[
"return x - y * floor(x / y);"
]
},
{
"op":"frexp",
"return_type":"float",
"args":[
"float x",
"out int exp"
],
"body":[
"float fexp;",
"float mantissa = frexp(abs(x), fexp) * sign(x);",
"exp = int(fexp);",
"return mantissa;"
]
},
{
"op":"frexp",
"return_type":"float2",
"args":[
"float2 x",
"out int2 exp"
],
"body":[
"float2 fexp;",
"float2 mantissa = frexp(abs(x), fexp) * sign(x);",
"exp = int2(fexp);",
"return mantissa;"
]
},
{
"op":"frexp",
"return_type":"float3",
"args":[
"float3 x",
"out int3 exp"
],
"body":[
"float3 fexp;",
"float3 mantissa = frexp(abs(x), fexp) * sign(x);",
"exp = int3(fexp);",
"return mantissa;"
]
},
{
"op":"frexp",
"return_type":"float4",
"args":[
"float4 x",
"out int4 exp"
],
"body":[
"float4 fexp;",
"float4 mantissa = frexp(abs(x), fexp) * sign(x);",
"exp = int4(fexp);",
"return mantissa;"
]
},
{
"op":"ldexp",
"return_type":"float",
"args":[
"float x",
"int exp"
],
"body":[
"return ldexp(x, float(exp));"
]
},
{
"op":"ldexp",
"return_type":"float2",
"args":[
"float2 x",
"int2 exp"
],
"body":[
"return ldexp(x, float2(exp));"
]
},
{
"op":"ldexp",
"return_type":"float3",
"args":[
"float3 x",
"int3 exp"
],
"body":[
"return ldexp(x, float3(exp));"
]
},
{
"op":"ldexp",
"return_type":"float4",
"args":[
"float4 x",
"int4 exp"
],
"body":[
"return ldexp(x, float4(exp));"
]
},
{
"op":"faceforward",
"return_type":"float",
"args":[
"float N",
"float I",
"float Nref"
],
"body":[
"if(dot(Nref, I) >= 0)",
"{",
" return -N;",
"}",
"else",
"{",
" return N;",
"}"
]
},
{
"op":"faceforward",
"return_type":"float2",
"args":[
"float2 N",
"float2 I",
"float2 Nref"
],
"body":[
"if(dot(Nref, I) >= 0)",
"{",
" return -N;",
"}",
"else",
"{",
" return N;",
"}"
]
},
{
"op":"faceforward",
"return_type":"float3",
"args":[
"float3 N",
"float3 I",
"float3 Nref"
],
"body":[
"if(dot(Nref, I) >= 0)",
"{",
" return -N;",
"}",
"else",
"{",
" return N;",
"}"
]
},
{
"op":"faceforward",
"return_type":"float4",
"args":[
"float4 N",
"float4 I",
"float4 Nref"
],
"body":[
"if(dot(Nref, I) >= 0)",
"{",
" return -N;",
"}",
"else",
"{",
" return N;",
"}"
]
},
{
"op":"atan",
"return_type":"float",
"args":[
"float y",
"float x"
],
"body":[
"if(x == 0 && y == 0) x = 1;",
"return atan2(y, x);"
]
},
{
"op":"atan",
"return_type":"float2",
"args":[
"float2 y",
"float2 x"
],
"body":[
"if(x[0] == 0 && y[0] == 0) x[0] = 1;",
"if(x[1] == 0 && y[1] == 0) x[1] = 1;",
"return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));"
]
},
{
"op":"atan",
"return_type":"float3",
"args":[
"float3 y",
"float3 x"
],
"body":[
"if(x[0] == 0 && y[0] == 0) x[0] = 1;",
"if(x[1] == 0 && y[1] == 0) x[1] = 1;",
"if(x[2] == 0 && y[2] == 0) x[2] = 1;",
"return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));"
]
},
{
"op":"atan",
"return_type":"float4",
"args":[
"float4 y",
"float4 x"
],
"body":[
"if(x[0] == 0 && y[0] == 0) x[0] = 1;",
"if(x[1] == 0 && y[1] == 0) x[1] = 1;",
"if(x[2] == 0 && y[2] == 0) x[2] = 1;",
"if(x[3] == 0 && y[3] == 0) x[3] = 1;",
"return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], ",
"x[2]), atan2(y[3], x[3]));"
]
},
{
"op":"asinh",
"return_type":"float",
"args":[
"in float x"
],
"body":[
"return log(x + sqrt(pow(x, 2.0) + 1.0));"
]
},
{
"op":"asinh",
"return_type":"float2",
"args":[
"in float2 x"
],
"body":[
"return log(x + sqrt(pow(x, 2.0) + 1.0));"
]
},
{
"op":"asinh",
"return_type":"float3",
"args":[
"in float3 x"
],
"body":[
"return log(x + sqrt(pow(x, 2.0) + 1.0));"
]
},
{
"op":"asinh",
"return_type":"float4",
"args":[
"in float4 x"
],
"body":[
"return log(x + sqrt(pow(x, 2.0) + 1.0));"
]
},
{
"op":"acosh",
"return_type":"float",
"args":[
"in float x"
],
"body":[
"return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));"
]
},
{
"op":"acosh",
"return_type":"float2",
"args":[
"in float2 x"
],
"body":[
"return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));"
]
},
{
"op":"acosh",
"return_type":"float3",
"args":[
"in float3 x"
],
"body":[
"return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));"
]
},
{
"op":"acosh",
"return_type":"float4",
"args":[
"in float4 x"
],
"body":[
"return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));"
]
},
{
"op":"atanh",
"return_type":"float",
"args":[
"in float x"
],
"body":[
"return 0.5 * log((1.0 + x) / (1.0 - x));"
]
},
{
"op":"atanh",
"return_type":"float2",
"args":[
"in float2 x"
],
"body":[
"return 0.5 * log((1.0 + x) / (1.0 - x));"
]
},
{
"op":"atanh",
"return_type":"float3",
"args":[
"in float3 x"
],
"body":[
"return 0.5 * log((1.0 + x) / (1.0 - x));"
]
},
{
"op":"atanh",
"return_type":"float4",
"args":[
"in float4 x"
],
"body":[
"return 0.5 * log((1.0 + x) / (1.0 - x));"
]
},
{
"op":"roundEven",
"return_type":"float",
"args":[
"in float x"
],
"body":[
"return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);"
]
},
{
"op":"roundEven",
"return_type":"float2",
"args":[
"in float2 x"
],
"body":[
"float2 v;",
"v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);",
"v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);",
"return v;"
]
},
{
"op":"roundEven",
"return_type":"float3",
"args":[
"in float3 x"
],
"body":[
"float3 v;",
"v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);",
"v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);",
"v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);",
"return v;"
]
},
{
"op":"roundEven",
"return_type":"float4",
"args":[
"in float4 x"
],
"body":[
"float4 v;",
"v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);",
"v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);",
"v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);",
"v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);",
"return v;"
]
},
{
"op":"packSnorm2x16",
"return_type":"uint",
"args":[
"in float2 v"
],
"helper":[
"int webgl_toSnorm16(in float x) {",
" return int(round(clamp(x, -1.0, 1.0) * 32767.0));",
"}"
],
"body":[
"int x = webgl_toSnorm16(v.x);",
"int y = webgl_toSnorm16(v.y);",
"return (asuint(y) << 16) | (asuint(x) & 0xffffu);"
]
},
{
"op":"packUnorm2x16",
"return_type":"uint",
"args":[
"in float2 v"
],
"helper":[
"uint webgl_toUnorm16(in float x) {",
" return uint(round(clamp(x, 0.0, 1.0) * 65535.0));",
"}"
],
"body":[
"uint x = webgl_toUnorm16(v.x);",
"uint y = webgl_toUnorm16(v.y);",
"return (y << 16) | x;"
]
},
{
"op":"packHalf2x16",
"return_type":"uint",
"args":[
"in float2 v"
],
"body":[
"uint x = f32tof16(v.x);",
"uint y = f32tof16(v.y);",
"return (y << 16) | x;"
]
},
{
"op":"unpackSnorm2x16",
"return_type":"float2",
"args":[
"in uint u"
],
"helper":[
"float webgl_fromSnorm16(in uint x) {",
" int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);",
" return clamp(float(xi) / 32767.0, -1.0, 1.0);",
"}"
],
"body":[
"uint y = (u >> 16);",
"uint x = u;",
"return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));"
]
},
{
"op":"unpackUnorm2x16",
"return_type":"float2",
"args":[
"in uint u"
],
"helper":[
"float webgl_fromUnorm16(in uint x) {",
" return float(x) / 65535.0;",
"}"
],
"body":[
"uint y = (u >> 16);",
"uint x = u & 0xffffu;",
"return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));"
]
},
{
"op":"unpackHalf2x16",
"return_type":"float2",
"args":[
"in uint u"
],
"body":[
"uint y = (u >> 16);",
"uint x = u & 0xffffu;",
"return float2(f16tof32(x), f16tof32(y));"
]
},
{
"op":"packSnorm4x8",
"return_type":"uint",
"args":[
"in float4 v"
],
"helper":[
"int webgl_toSnorm8(in float x) {",
" return int(round(clamp(x, -1.0, 1.0) * 127.0));",
"}"
],
"body":[
"int x = webgl_toSnorm8(v.x);",
"int y = webgl_toSnorm8(v.y);",
"int z = webgl_toSnorm8(v.z);",
"int w = webgl_toSnorm8(v.w);",
"return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) ",
"| ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);"
]
},
{
"op":"packUnorm4x8",
"return_type":"uint",
"args":[
"in float4 v"
],
"helper":[
"uint webgl_toUnorm8(in float x) {",
" return uint(round(clamp(x, 0.0, 1.0) * 255.0));",
"}"
],
"body":[
"uint x = webgl_toUnorm8(v.x);",
"uint y = webgl_toUnorm8(v.y);",
"uint z = webgl_toUnorm8(v.z);",
"uint w = webgl_toUnorm8(v.w);",
"return (w << 24) | (z << 16) | (y << 8) | x;"
]
},
{
"op":"unpackSnorm4x8",
"return_type":"float4",
"args":[
"in uint u"
],
"helper":[
"float webgl_fromSnorm8(in uint x) {",
" int xi = asint(x & 0x7fu) - asint(x & 0x80u);",
" return clamp(float(xi) / 127.0, -1.0, 1.0);",
"}"
],
"body":[
"uint w = (u >> 24);",
"uint z = (u >> 16);",
"uint y = (u >> 8);",
"uint x = u;",
"return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), ",
"webgl_fromSnorm8(z), webgl_fromSnorm8(w));"
]
},
{
"op":"unpackUnorm4x8",
"return_type":"float4",
"args":[
"in uint u"
],
"helper":[
"float webgl_fromUnorm8(in uint x) {",
" return float(x) / 255.0;",
"}"
],
"body":[
"uint w = (u >> 24) & 0xffu;",
"uint z = (u >> 16) & 0xffu;",
"uint y = (u >> 8) & 0xffu;",
"uint x = u & 0xffu;",
"return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), ",
"webgl_fromUnorm8(z), webgl_fromUnorm8(w));"
]
},
{
"comment":[
"The matrix resulting from outer product needs to be transposed",
"(matrices are stored as transposed to simplify element access in HLSL).",
"So the function should return transpose(c * r) where c is a column vector",
"and r is a row vector. This can be simplified by using the following",
"formula:",
"transpose(c * r) = transpose(r) * transpose(c)",
"transpose(r) and transpose(c) are in a sense free, since to get the",
"transpose of r, we simply can build a column matrix out of the original",
"vector instead of a row matrix."
],
"op":"outerProduct",
"return_type":"float2x2",
"args":[
"in float2 c",
"in float2 r"
],
"body":[
"return mul(float2x1(r), float1x2(c));"
]
},
{
"op":"outerProduct",
"return_type":"float3x3",
"args":[
"in float3 c",
"in float3 r"
],
"body":[
"return mul(float3x1(r), float1x3(c));"
]
},
{
"op":"outerProduct",
"return_type":"float4x4",
"args":[
"in float4 c",
"in float4 r"
],
"body":[
"return mul(float4x1(r), float1x4(c));"
]
},
{
"op":"outerProduct",
"return_type":"float2x3",
"args":[
"in float3 c",
"in float2 r"
],
"body":[
"return mul(float2x1(r), float1x3(c));"
]
},
{
"op":"outerProduct",
"return_type":"float3x2",
"args":[
"in float2 c",
"in float3 r"
],
"body":[
"return mul(float3x1(r), float1x2(c));"
]
},
{
"op":"outerProduct",
"return_type":"float2x4",
"args":[
"in float4 c",
"in float2 r"
],
"body":[
"return mul(float2x1(r), float1x4(c));"
]
},
{
"op":"outerProduct",
"return_type":"float4x2",
"args":[
"in float2 c",
"in float4 r"
],
"body":[
"return mul(float4x1(r), float1x2(c));"
]
},
{
"op":"outerProduct",
"return_type":"float3x4",
"args":[
"in float4 c",
"in float3 r"
],
"body":[
"return mul(float3x1(r), float1x4(c));"
]
},
{
"op":"outerProduct",
"return_type":"float4x3",
"args":[
"in float3 c",
"in float4 r"
],
"body":[
"return mul(float4x1(r), float1x3(c));"
]
},
{
"comment":[
"Remember here that the parameter matrix is actually the transpose",
"of the matrix that we're trying to invert, and the resulting matrix",
"should also be the transpose of the inverse.",
"When accessing the parameter matrix with m[a][b] it can be thought of so",
"that a is the column and b is the row of the matrix that we're inverting.",
"We calculate the inverse as the adjugate matrix divided by the",
"determinant of the matrix being inverted. However, as the result needs",
"to be transposed, we actually use of the transpose of the adjugate matrix",
"which happens to be the cofactor matrix. That's stored in 'cof'.",
"We don't need to care about divide-by-zero since results are undefined",
"for singular or poorly-conditioned matrices."
],
"op":"inverse",
"return_type":"float2x2",
"args":[
"in float2x2 m"
],
"body":[
"float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };",
"return cof / determinant(transpose(m));"
]
},
{
"comment":[
"cofAB is the cofactor for column A and row B."
],
"op":"inverse",
"return_type":"float3x3",
"args":[
"in float3x3 m"
],
"body":[
"float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];",
"float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);",
"float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];",
"float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);",
"float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];",
"float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);",
"float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];",
"float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);",
"float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];",
"float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };",
"return cof / determinant(transpose(m));"
]
},
{
"op":"inverse",
"return_type":"float4x4",
"args":[
"in float4x4 m"
],
"body":[
"float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * ",
"m[1][2] * m[2][3]",
" - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * ",
"m[1][3];",
"float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * ",
"m[1][2] * m[2][3]",
" - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * ",
"m[1][3]);",
"float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * ",
"m[1][1] * m[2][3]",
" - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * ",
"m[1][3];",
"float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * ",
"m[1][1] * m[2][2]",
" - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * ",
"m[1][2]);",
"float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * ",
"m[0][2] * m[2][3]",
" - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * ",
"m[0][3]);",
"float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * ",
"m[0][2] * m[2][3]",
" - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * ",
"m[0][3];",
"float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * ",
"m[0][1] * m[2][3]",
" - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * ",
"m[0][3]);",
"float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * ",
"m[0][1] * m[2][2]",
" - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * ",
"m[0][2];",
"float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * ",
"m[0][2] * m[1][3]",
" - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * ",
"m[0][3];",
"float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * ",
"m[0][2] * m[1][3]",
" - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * ",
"m[0][3]);",
"float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * ",
"m[0][1] * m[1][3]",
" - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * ",
"m[0][3];",
"float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * ",
"m[0][1] * m[1][2]",
" - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * ",
"m[0][2]);",
"float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * ",
"m[0][2] * m[1][3]",
" - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * ",
"m[0][3]);",
"float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * ",
"m[0][2] * m[1][3]",
" - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * ",
"m[0][3];",
"float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * ",
"m[0][1] * m[1][3]",
" - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * ",
"m[0][3]);",
"float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * ",
"m[0][1] * m[1][2]",
" - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * ",
"m[0][2];",
"float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,",
" cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };",
"return cof / determinant(transpose(m));"
]
},
{
"comment":[
"Emulate ESSL3 variant of mix that takes last argument as boolean vector.",
"genType mix(genType x, genType y, genBType a): Selects which vector each returned component",
"comes from. For a component of 'a' that is false, the corresponding component of 'x' is",
"returned. For a component of 'a' that is true, the corresponding component of 'y' is returned."
],
"op":"mix",
"return_type":"float",
"args":[
"float x",
"float y",
"bool a"
],
"body":[
"return a ? y : x;"
]
},
{
"op":"mix",
"return_type":"float2",
"args":[
"float2 x",
"float2 y",
"bool2 a"
],
"body":[
"return a ? y : x;"
]
},
{
"op":"mix",
"return_type":"float3",
"args":[
"float3 x",
"float3 y",
"bool3 a"
],
"body":[
"return a ? y : x;"
]
},
{
"op":"mix",
"return_type":"float4",
"args":[
"float4 x",
"float4 y",
"bool4 a"
],
"body":[
"return a ? y : x;"
]
},
{
"op":"bitfieldExtract",
"return_type":"uint",
"args":[
"uint value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return 0u;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"return (value & mask) >> offset;"
]
},
{
"op":"bitfieldExtract",
"return_type":"uint2",
"args":[
"uint2 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return uint2(0u, 0u);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"return (value & mask) >> offset;"
]
},
{
"op":"bitfieldExtract",
"return_type":"uint3",
"args":[
"uint3 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return uint3(0u, 0u, 0u);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"return (value & mask) >> offset;"
]
},
{
"op":"bitfieldExtract",
"return_type":"uint4",
"args":[
"uint4 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return uint4(0u, 0u, 0u, 0u);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"return (value & mask) >> offset;"
]
},
{
"op":"bitfieldExtract",
"return_type":"int",
"args":[
"int value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return 0;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint resultUnsigned = (asuint(value) & mask) >> offset;",
"if (bits != 32 && (resultUnsigned & maskMsb) != 0)",
"{",
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;",
" resultUnsigned |= higherBitsMask;",
"}",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldExtract",
"return_type":"int2",
"args":[
"int2 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return int2(0, 0);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint2 resultUnsigned = (asuint(value) & mask) >> offset;",
"if (bits != 32)",
"{",
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;",
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;",
"}",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldExtract",
"return_type":"int3",
"args":[
"int3 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return int3(0, 0, 0);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint3 resultUnsigned = (asuint(value) & mask) >> offset;",
"if (bits != 32)",
"{",
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;",
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;",
"}",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldExtract",
"return_type":"int4",
"args":[
"int4 value",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return int4(0, 0, 0, 0);",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint mask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint4 resultUnsigned = (asuint(value) & mask) >> offset;",
"if (bits != 32)",
"{",
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;",
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;",
"}",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldInsert",
"return_type":"uint",
"args":[
"uint base",
"uint insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"return (base & baseMask) | ((insert << offset) & insertMask);"
]
},
{
"op":"bitfieldInsert",
"return_type":"uint2",
"args":[
"uint2 base",
"uint2 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"return (base & baseMask) | ((insert << offset) & insertMask);"
]
},
{
"op":"bitfieldInsert",
"return_type":"uint3",
"args":[
"uint3 base",
"uint3 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"return (base & baseMask) | ((insert << offset) & insertMask);"
]
},
{
"op":"bitfieldInsert",
"return_type":"uint4",
"args":[
"uint4 base",
"uint4 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"return (base & baseMask) | ((insert << offset) & insertMask);"
]
},
{
"op":"bitfieldInsert",
"return_type":"int",
"args":[
"int base",
"int insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ",
" insertMask);",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldInsert",
"return_type":"int2",
"args":[
"int2 base",
"int2 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ",
" insertMask);",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldInsert",
"return_type":"int3",
"args":[
"int3 base",
"int3 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ",
" insertMask);",
"return asint(resultUnsigned);"
]
},
{
"op":"bitfieldInsert",
"return_type":"int4",
"args":[
"int4 base",
"int4 insert",
"int offset",
"int bits"
],
"body":[
"if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)",
"{",
" return base;",
"}",
"uint maskMsb = (1u << (bits - 1));",
"uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;",
"uint baseMask = ~insertMask;",
"uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ",
"insertMask);",
"return asint(resultUnsigned);"
]
},
{
"op":"uaddCarry",
"return_type":"uint",
"args":[
"uint x",
"uint y",
"out uint carry"
],
"body":[
"carry = uint(x > (0xffffffffu - y));",
"return x + y;"
]
},
{
"op":"uaddCarry",
"return_type":"uint2",
"args":[
"uint2 x",
"uint2 y",
"out uint2 carry"
],
"body":[
"carry = uint2(x > (0xffffffffu - y));",
"return x + y;"
]
},
{
"op":"uaddCarry",
"return_type":"uint3",
"args":[
"uint3 x",
"uint3 y",
"out uint3 carry"
],
"body":[
"carry = uint3(x > (0xffffffffu - y));",
"return x + y;"
]
},
{
"op":"uaddCarry",
"return_type":"uint4",
"args":[
"uint4 x",
"uint4 y",
"out uint4 carry"
],
"body":[
"carry = uint4(x > (0xffffffffu - y));",
"return x + y;"
]
},
{
"op":"usubBorrow",
"return_type":"uint",
"args":[
"uint x",
"uint y",
"out uint borrow"
],
"body":[
"borrow = uint(x < y);",
"return x - y;"
]
},
{
"op":"usubBorrow",
"return_type":"uint2",
"args":[
"uint2 x",
"uint2 y",
"out uint2 borrow"
],
"body":[
"borrow = uint2(x < y);",
"return x - y;"
]
},
{
"op":"usubBorrow",
"return_type":"uint3",
"args":[
"uint3 x",
"uint3 y",
"out uint3 borrow"
],
"body":[
"borrow = uint3(x < y);",
"return x - y;"
]
},
{
"op":"usubBorrow",
"return_type":"uint4",
"args":[
"uint4 x",
"uint4 y",
"out uint4 borrow"
],
"body":[
"borrow = uint4(x < y);",
"return x - y;"
]
}
]
// GENERATED FILE - DO NOT EDIT.
// Generated by gen_emulated_builtin_function_tables.py using data from
// emulated_builtin_function_data_hlsl.json.
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// emulated_builtin_functions_hlsl:
// HLSL code for emulating GLSL builtin functions not present in HLSL.
#include "compiler/translator/BuiltInFunctionEmulator.h"
namespace sh
{
namespace
{
constexpr std::pair<MiniFunctionId, const char *> g_hlslFunctions[] = {
{{EOpMod, ParamType::Float1, ParamType::Float1},
"float webgl_mod_emu(float x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float2, ParamType::Float2},
"float2 webgl_mod_emu(float2 x, float2 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float2, ParamType::Float1},
"float2 webgl_mod_emu(float2 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float3, ParamType::Float3},
"float3 webgl_mod_emu(float3 x, float3 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float3, ParamType::Float1},
"float3 webgl_mod_emu(float3 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float4, ParamType::Float4},
"float4 webgl_mod_emu(float4 x, float4 y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpMod, ParamType::Float4, ParamType::Float1},
"float4 webgl_mod_emu(float4 x, float y)\n"
"{\n"
" return x - y * floor(x / y);\n"
"}\n"},
{{EOpFrexp, ParamType::Float1, ParamType::Int1},
"float webgl_frexp_emu(float x, out int exp)\n"
"{\n"
" float fexp;\n"
" float mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int(fexp);\n"
" return mantissa;\n"
"}\n"},
{{EOpFrexp, ParamType::Float2, ParamType::Int2},
"float2 webgl_frexp_emu(float2 x, out int2 exp)\n"
"{\n"
" float2 fexp;\n"
" float2 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int2(fexp);\n"
" return mantissa;\n"
"}\n"},
{{EOpFrexp, ParamType::Float3, ParamType::Int3},
"float3 webgl_frexp_emu(float3 x, out int3 exp)\n"
"{\n"
" float3 fexp;\n"
" float3 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int3(fexp);\n"
" return mantissa;\n"
"}\n"},
{{EOpFrexp, ParamType::Float4, ParamType::Int4},
"float4 webgl_frexp_emu(float4 x, out int4 exp)\n"
"{\n"
" float4 fexp;\n"
" float4 mantissa = frexp(abs(x), fexp) * sign(x);\n"
" exp = int4(fexp);\n"
" return mantissa;\n"
"}\n"},
{{EOpLdexp, ParamType::Float1, ParamType::Int1},
"float webgl_ldexp_emu(float x, int exp)\n"
"{\n"
" return ldexp(x, float(exp));\n"
"}\n"},
{{EOpLdexp, ParamType::Float2, ParamType::Int2},
"float2 webgl_ldexp_emu(float2 x, int2 exp)\n"
"{\n"
" return ldexp(x, float2(exp));\n"
"}\n"},
{{EOpLdexp, ParamType::Float3, ParamType::Int3},
"float3 webgl_ldexp_emu(float3 x, int3 exp)\n"
"{\n"
" return ldexp(x, float3(exp));\n"
"}\n"},
{{EOpLdexp, ParamType::Float4, ParamType::Int4},
"float4 webgl_ldexp_emu(float4 x, int4 exp)\n"
"{\n"
" return ldexp(x, float4(exp));\n"
"}\n"},
{{EOpFaceforward, ParamType::Float1, ParamType::Float1, ParamType::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"},
{{EOpFaceforward, ParamType::Float2, ParamType::Float2, ParamType::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"},
{{EOpFaceforward, ParamType::Float3, ParamType::Float3, ParamType::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"},
{{EOpFaceforward, ParamType::Float4, ParamType::Float4, ParamType::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"},
{{EOpAtan, ParamType::Float1, ParamType::Float1},
"float webgl_atan_emu(float y, float x)\n"
"{\n"
" if(x == 0 && y == 0) x = 1;\n"
" return atan2(y, x);\n"
"}\n"},
{{EOpAtan, ParamType::Float2, ParamType::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"},
{{EOpAtan, ParamType::Float3, ParamType::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"},
{{EOpAtan, ParamType::Float4, ParamType::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], \n"
" x[2]), atan2(y[3], x[3]));\n"
"}\n"},
{{EOpAsinh, ParamType::Float1},
"float webgl_asinh_emu(in float x)\n"
"{\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n"},
{{EOpAsinh, ParamType::Float2},
"float2 webgl_asinh_emu(in float2 x)\n"
"{\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n"},
{{EOpAsinh, ParamType::Float3},
"float3 webgl_asinh_emu(in float3 x)\n"
"{\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n"},
{{EOpAsinh, ParamType::Float4},
"float4 webgl_asinh_emu(in float4 x)\n"
"{\n"
" return log(x + sqrt(pow(x, 2.0) + 1.0));\n"
"}\n"},
{{EOpAcosh, ParamType::Float1},
"float webgl_acosh_emu(in float x)\n"
"{\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n"},
{{EOpAcosh, ParamType::Float2},
"float2 webgl_acosh_emu(in float2 x)\n"
"{\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n"},
{{EOpAcosh, ParamType::Float3},
"float3 webgl_acosh_emu(in float3 x)\n"
"{\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n"},
{{EOpAcosh, ParamType::Float4},
"float4 webgl_acosh_emu(in float4 x)\n"
"{\n"
" return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n"
"}\n"},
{{EOpAtanh, ParamType::Float1},
"float webgl_atanh_emu(in float x)\n"
"{\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n"},
{{EOpAtanh, ParamType::Float2},
"float2 webgl_atanh_emu(in float2 x)\n"
"{\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n"},
{{EOpAtanh, ParamType::Float3},
"float3 webgl_atanh_emu(in float3 x)\n"
"{\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n"},
{{EOpAtanh, ParamType::Float4},
"float4 webgl_atanh_emu(in float4 x)\n"
"{\n"
" return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n"},
{{EOpRoundEven, ParamType::Float1},
"float webgl_roundEven_emu(in float x)\n"
"{\n"
" return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n"
"}\n"},
{{EOpRoundEven, ParamType::Float2},
"float2 webgl_roundEven_emu(in float2 x)\n"
"{\n"
" float2 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" return v;\n"
"}\n"},
{{EOpRoundEven, ParamType::Float3},
"float3 webgl_roundEven_emu(in float3 x)\n"
"{\n"
" float3 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
" return v;\n"
"}\n"},
{{EOpRoundEven, ParamType::Float4},
"float4 webgl_roundEven_emu(in float4 x)\n"
"{\n"
" float4 v;\n"
" v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n"
" v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n"
" v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n"
" v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n"
" return v;\n"
"}\n"},
{{EOpPackSnorm2x16, ParamType::Float2},
"int webgl_toSnorm16(in float x) {\n"
" return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
"}\n"
"uint webgl_packSnorm2x16_emu(in float2 v)\n"
"{\n"
" int x = webgl_toSnorm16(v.x);\n"
" int y = webgl_toSnorm16(v.y);\n"
" return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
"}\n"},
{{EOpPackUnorm2x16, ParamType::Float2},
"uint webgl_toUnorm16(in float x) {\n"
" return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
"}\n"
"uint webgl_packUnorm2x16_emu(in float2 v)\n"
"{\n"
" uint x = webgl_toUnorm16(v.x);\n"
" uint y = webgl_toUnorm16(v.y);\n"
" return (y << 16) | x;\n"
"}\n"},
{{EOpPackHalf2x16, ParamType::Float2},
"uint webgl_packHalf2x16_emu(in float2 v)\n"
"{\n"
" uint x = f32tof16(v.x);\n"
" uint y = f32tof16(v.y);\n"
" return (y << 16) | x;\n"
"}\n"},
{{EOpUnpackSnorm2x16, ParamType::Uint1},
"float webgl_fromSnorm16(in uint x) {\n"
" int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
"}\n"
"float2 webgl_unpackSnorm2x16_emu(in uint u)\n"
"{\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
" return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n"
"}\n"},
{{EOpUnpackUnorm2x16, ParamType::Uint1},
"float webgl_fromUnorm16(in uint x) {\n"
" return float(x) / 65535.0;\n"
"}\n"
"float2 webgl_unpackUnorm2x16_emu(in uint u)\n"
"{\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n"
"}\n"},
{{EOpUnpackHalf2x16, ParamType::Uint1},
"float2 webgl_unpackHalf2x16_emu(in uint u)\n"
"{\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return float2(f16tof32(x), f16tof32(y));\n"
"}\n"},
{{EOpPackSnorm4x8, ParamType::Float4},
"int webgl_toSnorm8(in float x) {\n"
" return int(round(clamp(x, -1.0, 1.0) * 127.0));\n"
"}\n"
"uint webgl_packSnorm4x8_emu(in float4 v)\n"
"{\n"
" int x = webgl_toSnorm8(v.x);\n"
" int y = webgl_toSnorm8(v.y);\n"
" int z = webgl_toSnorm8(v.z);\n"
" int w = webgl_toSnorm8(v.w);\n"
" return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) \n"
" | ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n"
"}\n"},
{{EOpPackUnorm4x8, ParamType::Float4},
"uint webgl_toUnorm8(in float x) {\n"
" return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n"
"}\n"
"uint webgl_packUnorm4x8_emu(in float4 v)\n"
"{\n"
" uint x = webgl_toUnorm8(v.x);\n"
" uint y = webgl_toUnorm8(v.y);\n"
" uint z = webgl_toUnorm8(v.z);\n"
" uint w = webgl_toUnorm8(v.w);\n"
" return (w << 24) | (z << 16) | (y << 8) | x;\n"
"}\n"},
{{EOpUnpackSnorm4x8, ParamType::Uint1},
"float webgl_fromSnorm8(in uint x) {\n"
" int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n"
" return clamp(float(xi) / 127.0, -1.0, 1.0);\n"
"}\n"
"float4 webgl_unpackSnorm4x8_emu(in uint u)\n"
"{\n"
" uint w = (u >> 24);\n"
" uint z = (u >> 16);\n"
" uint y = (u >> 8);\n"
" uint x = u;\n"
" return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), \n"
" webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n"
"}\n"},
{{EOpUnpackUnorm4x8, ParamType::Uint1},
"float webgl_fromUnorm8(in uint x) {\n"
" return float(x) / 255.0;\n"
"}\n"
"float4 webgl_unpackUnorm4x8_emu(in uint u)\n"
"{\n"
" uint w = (u >> 24) & 0xffu;\n"
" uint z = (u >> 16) & 0xffu;\n"
" uint y = (u >> 8) & 0xffu;\n"
" uint x = u & 0xffu;\n"
" return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), \n"
" webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n"
"}\n"},
// The matrix resulting from outer product needs to be transposed
// (matrices are stored as transposed to simplify element access in HLSL).
// So the function should return transpose(c * r) where c is a column vector
// and r is a row vector. This can be simplified by using the following
// formula:
// transpose(c * r) = transpose(r) * transpose(c)
// transpose(r) and transpose(c) are in a sense free, since to get the
// transpose of r, we simply can build a column matrix out of the original
// vector instead of a row matrix.
{{EOpOuterProduct, ParamType::Float2, ParamType::Float2},
"float2x2 webgl_outerProduct_emu(in float2 c, in float2 r)\n"
"{\n"
" return mul(float2x1(r), float1x2(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float3, ParamType::Float3},
"float3x3 webgl_outerProduct_emu(in float3 c, in float3 r)\n"
"{\n"
" return mul(float3x1(r), float1x3(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float4, ParamType::Float4},
"float4x4 webgl_outerProduct_emu(in float4 c, in float4 r)\n"
"{\n"
" return mul(float4x1(r), float1x4(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float3, ParamType::Float2},
"float2x3 webgl_outerProduct_emu(in float3 c, in float2 r)\n"
"{\n"
" return mul(float2x1(r), float1x3(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float2, ParamType::Float3},
"float3x2 webgl_outerProduct_emu(in float2 c, in float3 r)\n"
"{\n"
" return mul(float3x1(r), float1x2(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float4, ParamType::Float2},
"float2x4 webgl_outerProduct_emu(in float4 c, in float2 r)\n"
"{\n"
" return mul(float2x1(r), float1x4(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float2, ParamType::Float4},
"float4x2 webgl_outerProduct_emu(in float2 c, in float4 r)\n"
"{\n"
" return mul(float4x1(r), float1x2(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float4, ParamType::Float3},
"float3x4 webgl_outerProduct_emu(in float4 c, in float3 r)\n"
"{\n"
" return mul(float3x1(r), float1x4(c));\n"
"}\n"},
{{EOpOuterProduct, ParamType::Float3, ParamType::Float4},
"float4x3 webgl_outerProduct_emu(in float3 c, in float4 r)\n"
"{\n"
" return mul(float4x1(r), float1x3(c));\n"
"}\n"},
// Remember here that the parameter matrix is actually the transpose
// of the matrix that we're trying to invert, and the resulting matrix
// should also be the transpose of the inverse.
// When accessing the parameter matrix with m[a][b] it can be thought of so
// that a is the column and b is the row of the matrix that we're inverting.
// We calculate the inverse as the adjugate matrix divided by the
// determinant of the matrix being inverted. However, as the result needs
// to be transposed, we actually use of the transpose of the adjugate matrix
// which happens to be the cofactor matrix. That's stored in 'cof'.
// We don't need to care about divide-by-zero since results are undefined
// for singular or poorly-conditioned matrices.
{{EOpInverse, ParamType::Mat2},
"float2x2 webgl_inverse_emu(in float2x2 m)\n"
"{\n"
" float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n"
" return cof / determinant(transpose(m));\n"
"}\n"},
// cofAB is the cofactor for column A and row B.
{{EOpInverse, ParamType::Mat3},
"float3x3 webgl_inverse_emu(in float3x3 m)\n"
"{\n"
" float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n"
" float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n"
" float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n"
" float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n"
" float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n"
" float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n"
" float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n"
" float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n"
" float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n"
" float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n"
" return cof / determinant(transpose(m));\n"
"}\n"},
{{EOpInverse, ParamType::Mat4},
"float4x4 webgl_inverse_emu(in float4x4 m)\n"
"{\n"
" float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * \n"
" m[1][2] * m[2][3]\n"
" - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * \n"
" m[1][3];\n"
" float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * \n"
" m[1][2] * m[2][3]\n"
" - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * \n"
" m[1][3]);\n"
" float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * \n"
" m[1][1] * m[2][3]\n"
" - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * \n"
" m[1][3];\n"
" float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * \n"
" m[1][1] * m[2][2]\n"
" - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * \n"
" m[1][2]);\n"
" float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * \n"
" m[0][2] * m[2][3]\n"
" - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * \n"
" m[0][3]);\n"
" float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * \n"
" m[0][2] * m[2][3]\n"
" - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * \n"
" m[0][3];\n"
" float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * \n"
" m[0][1] * m[2][3]\n"
" - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * \n"
" m[0][3]);\n"
" float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * \n"
" m[0][1] * m[2][2]\n"
" - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * \n"
" m[0][2];\n"
" float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * \n"
" m[0][2] * m[1][3]\n"
" - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * \n"
" m[0][3];\n"
" float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * \n"
" m[0][2] * m[1][3]\n"
" - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * \n"
" m[0][3]);\n"
" float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * \n"
" m[0][1] * m[1][3]\n"
" - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * \n"
" m[0][3];\n"
" float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * \n"
" m[0][1] * m[1][2]\n"
" - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * \n"
" m[0][2]);\n"
" float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * \n"
" m[0][2] * m[1][3]\n"
" - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * \n"
" m[0][3]);\n"
" float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * \n"
" m[0][2] * m[1][3]\n"
" - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * \n"
" m[0][3];\n"
" float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * \n"
" m[0][1] * m[1][3]\n"
" - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * \n"
" m[0][3]);\n"
" float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * \n"
" m[0][1] * m[1][2]\n"
" - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * \n"
" m[0][2];\n"
" float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,\n"
" cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n"
" return cof / determinant(transpose(m));\n"
"}\n"},
// Emulate ESSL3 variant of mix that takes last argument as boolean vector.
// genType mix(genType x, genType y, genBType a): Selects which vector each returned component
// comes from. For a component of 'a' that is false, the corresponding component of 'x' is
// returned. For a component of 'a' that is true, the corresponding component of 'y' is
// returned.
{{EOpMix, ParamType::Float1, ParamType::Float1, ParamType::Bool1},
"float webgl_mix_emu(float x, float y, bool a)\n"
"{\n"
" return a ? y : x;\n"
"}\n"},
{{EOpMix, ParamType::Float2, ParamType::Float2, ParamType::Bool2},
"float2 webgl_mix_emu(float2 x, float2 y, bool2 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n"},
{{EOpMix, ParamType::Float3, ParamType::Float3, ParamType::Bool3},
"float3 webgl_mix_emu(float3 x, float3 y, bool3 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n"},
{{EOpMix, ParamType::Float4, ParamType::Float4, ParamType::Bool4},
"float4 webgl_mix_emu(float4 x, float4 y, bool4 a)\n"
"{\n"
" return a ? y : x;\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Uint1, ParamType::Int1, ParamType::Int1},
"uint webgl_bitfieldExtract_emu(uint value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return 0u;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Uint2, ParamType::Int1, ParamType::Int1},
"uint2 webgl_bitfieldExtract_emu(uint2 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint2(0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Uint3, ParamType::Int1, ParamType::Int1},
"uint3 webgl_bitfieldExtract_emu(uint3 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint3(0u, 0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Uint4, ParamType::Int1, ParamType::Int1},
"uint4 webgl_bitfieldExtract_emu(uint4 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return uint4(0u, 0u, 0u, 0u);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" return (value & mask) >> offset;\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Int1, ParamType::Int1, ParamType::Int1},
"int webgl_bitfieldExtract_emu(int value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return 0;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32 && (resultUnsigned & maskMsb) != 0)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Int2, ParamType::Int1, ParamType::Int1},
"int2 webgl_bitfieldExtract_emu(int2 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int2(0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint2 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Int3, ParamType::Int1, ParamType::Int1},
"int3 webgl_bitfieldExtract_emu(int3 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int3(0, 0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint3 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldExtract, ParamType::Int4, ParamType::Int1, ParamType::Int1},
"int4 webgl_bitfieldExtract_emu(int4 value, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return int4(0, 0, 0, 0);\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint4 resultUnsigned = (asuint(value) & mask) >> offset;\n"
" if (bits != 32)\n"
" {\n"
" uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n"
" resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n"
" }\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Uint1, ParamType::Uint1, ParamType::Int1, ParamType::Int1},
"uint webgl_bitfieldInsert_emu(uint base, uint insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Uint2, ParamType::Uint2, ParamType::Int1, ParamType::Int1},
"uint2 webgl_bitfieldInsert_emu(uint2 base, uint2 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Uint3, ParamType::Uint3, ParamType::Int1, ParamType::Int1},
"uint3 webgl_bitfieldInsert_emu(uint3 base, uint3 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Uint4, ParamType::Uint4, ParamType::Int1, ParamType::Int1},
"uint4 webgl_bitfieldInsert_emu(uint4 base, uint4 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" return (base & baseMask) | ((insert << offset) & insertMask);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Int1, ParamType::Int1, ParamType::Int1, ParamType::Int1},
"int webgl_bitfieldInsert_emu(int base, int insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
" insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Int2, ParamType::Int2, ParamType::Int1, ParamType::Int1},
"int2 webgl_bitfieldInsert_emu(int2 base, int2 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
" insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Int3, ParamType::Int3, ParamType::Int1, ParamType::Int1},
"int3 webgl_bitfieldInsert_emu(int3 base, int3 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
" insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpBitfieldInsert, ParamType::Int4, ParamType::Int4, ParamType::Int1, ParamType::Int1},
"int4 webgl_bitfieldInsert_emu(int4 base, int4 insert, int offset, int bits)\n"
"{\n"
" if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n"
" {\n"
" return base;\n"
" }\n"
" uint maskMsb = (1u << (bits - 1));\n"
" uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n"
" uint baseMask = ~insertMask;\n"
" uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n"
" insertMask);\n"
" return asint(resultUnsigned);\n"
"}\n"},
{{EOpUaddCarry, ParamType::Uint1, ParamType::Uint1, ParamType::Uint1},
"uint webgl_uaddCarry_emu(uint x, uint y, out uint carry)\n"
"{\n"
" carry = uint(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n"},
{{EOpUaddCarry, ParamType::Uint2, ParamType::Uint2, ParamType::Uint2},
"uint2 webgl_uaddCarry_emu(uint2 x, uint2 y, out uint2 carry)\n"
"{\n"
" carry = uint2(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n"},
{{EOpUaddCarry, ParamType::Uint3, ParamType::Uint3, ParamType::Uint3},
"uint3 webgl_uaddCarry_emu(uint3 x, uint3 y, out uint3 carry)\n"
"{\n"
" carry = uint3(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n"},
{{EOpUaddCarry, ParamType::Uint4, ParamType::Uint4, ParamType::Uint4},
"uint4 webgl_uaddCarry_emu(uint4 x, uint4 y, out uint4 carry)\n"
"{\n"
" carry = uint4(x > (0xffffffffu - y));\n"
" return x + y;\n"
"}\n"},
{{EOpUsubBorrow, ParamType::Uint1, ParamType::Uint1, ParamType::Uint1},
"uint webgl_usubBorrow_emu(uint x, uint y, out uint borrow)\n"
"{\n"
" borrow = uint(x < y);\n"
" return x - y;\n"
"}\n"},
{{EOpUsubBorrow, ParamType::Uint2, ParamType::Uint2, ParamType::Uint2},
"uint2 webgl_usubBorrow_emu(uint2 x, uint2 y, out uint2 borrow)\n"
"{\n"
" borrow = uint2(x < y);\n"
" return x - y;\n"
"}\n"},
{{EOpUsubBorrow, ParamType::Uint3, ParamType::Uint3, ParamType::Uint3},
"uint3 webgl_usubBorrow_emu(uint3 x, uint3 y, out uint3 borrow)\n"
"{\n"
" borrow = uint3(x < y);\n"
" return x - y;\n"
"}\n"},
{{EOpUsubBorrow, ParamType::Uint4, ParamType::Uint4, ParamType::Uint4},
"uint4 webgl_usubBorrow_emu(uint4 x, uint4 y, out uint4 borrow)\n"
"{\n"
" borrow = uint4(x < y);\n"
" return x - y;\n"
"}\n"},
};
} // anonymous namespace
const char *FindHLSLFunction(const FunctionId &functionID)
{
for (size_t index = 0; index < ArraySize(g_hlslFunctions); ++index)
{
const auto &function = g_hlslFunctions[index];
if (function.first == functionID)
{
return function.second;
}
}
return nullptr;
}
} // namespace sh
#!/usr/bin/python
# Copyright 2017 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# gen_emulated_builtin_function_tables.py:
# Generator for the builtin function maps.
from datetime import date
import json
import os, sys
template_emulated_builtin_functions_hlsl = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}.
//
// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// emulated_builtin_functions_hlsl:
// HLSL code for emulating GLSL builtin functions not present in HLSL.
#include "compiler/translator/BuiltInFunctionEmulator.h"
namespace sh
{{
namespace
{{
constexpr std::pair<MiniFunctionId, const char *> g_hlslFunctions[] = {{
{emulated_functions}}};
}} // anonymous namespace
const char *FindHLSLFunction(const FunctionId &functionID)
{{
for (size_t index = 0; index < ArraySize(g_hlslFunctions); ++index)
{{
const auto &function = g_hlslFunctions[index];
if (function.first == functionID)
{{
return function.second;
}}
}}
return nullptr;
}}
}} // namespace sh
"""
def reject_duplicate_keys(pairs):
found_keys = {}
for key, value in pairs:
if key in found_keys:
raise ValueError("duplicate key: %r" % (key,))
else:
found_keys[key] = value
return found_keys
def load_json(path):
with open(path) as map_file:
file_data = map_file.read()
map_file.close()
return json.loads(file_data, object_pairs_hook=reject_duplicate_keys)
def enum_type(arg):
# handle 'argtype argname' and 'out argtype argname'
chunks = arg.split(' ')
arg_type = chunks[0]
if len(chunks) == 3:
arg_type = chunks[1]
if arg_type == "float2x2":
return "Mat2"
elif arg_type == "float3x3":
return "Mat3"
elif arg_type == "float4x4":
return "Mat4"
suffix = ""
if not arg_type[-1].isdigit():
suffix = '1'
return arg_type.capitalize() + suffix
def caps(op):
return op[0].upper() + op[1:]
input_script = "emulated_builtin_function_data_hlsl.json"
hlsl_json = load_json(input_script)
emulated_functions = []
def gen_emulated_function(data):
func = ""
if 'comment' in data:
func += "".join([ "// " + line + "\n" for line in data['comment'] ])
sig = data['return_type'] + ' webgl_' + data['op'] + '_emu(' + ', '.join(data['args']) + ')'
body = [ sig, '{' ] + [' ' + line for line in data['body']] + ['}']
func += "{\n"
func += "{ EOp" + caps(data['op']) + ", " + ", ".join("ParamType::" + enum_type(arg) for arg in data['args']) + " },\n"
if 'helper' in data:
func += '"' + '\\n"\n"'.join(data['helper']) + '\\n"\n'
func += '"' + '\\n"\n"'.join(body) + '\\n"\n'
func += "},\n"
return [ func ]
for item in hlsl_json:
emulated_functions += gen_emulated_function(item)
hlsl_fname = "emulated_builtin_functions_hlsl_autogen.cpp"
hlsl_gen = template_emulated_builtin_functions_hlsl.format(
script_name = sys.argv[0],
data_source_name = input_script,
copyright_year = date.today().year,
emulated_functions = "".join(emulated_functions))
with open(hlsl_fname, 'wt') as f:
f.write(hlsl_gen)
f.close()
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