Commit 7700ff65 by Olli Etuaho

Add basic support for ESSL3 vec2 (un)pack functions

The functions are emulated on HLSL, and use the native functions on OpenGL 4.2+ and GLES3.0. Emulation for OpenGL versions <= 4.1 is not yet implemented. BUG=angle:865 Change-Id: I6803a1767dacdb3dca12f13924651fd38fcacb75 Reviewed-on: https://chromium-review.googlesource.com/240961Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent 958db2b6
...@@ -194,6 +194,63 @@ BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL() ...@@ -194,6 +194,63 @@ BuiltInFunctionEmulatorHLSL::BuiltInFunctionEmulatorHLSL()
" return 0.5 * log((1.0 + x) / (1.0 - x));\n" " return 0.5 * log((1.0 + x) / (1.0 - x));\n"
"}\n"); "}\n");
AddEmulatedFunction(EOpPackSnorm2x16, float2,
"int webgl_toSnorm(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_toSnorm(v.x);\n"
" int y = webgl_toSnorm(v.y);\n"
" return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
"}\n");
AddEmulatedFunction(EOpPackUnorm2x16, float2,
"uint webgl_toUnorm(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_toUnorm(v.x);\n"
" uint y = webgl_toUnorm(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
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");
TType uint1(EbtUInt);
AddEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(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_fromSnorm(x), webgl_fromSnorm(y));\n"
"}\n");
AddEmulatedFunction(EOpUnpackUnorm2x16, uint1,
"float webgl_fromUnorm(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_fromUnorm(x), webgl_fromUnorm(y));\n"
"}\n");
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");
// The matrix resulting from outer product needs to be transposed // The matrix resulting from outer product needs to be transposed
// (matrices are stored as transposed to simplify element access in HLSL). // (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 // So the function should return transpose(c * r) where c is a column vector
......
...@@ -252,6 +252,13 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR ...@@ -252,6 +252,13 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "uintBitsToFloat", uint3); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "uintBitsToFloat", uint3);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "uintBitsToFloat", uint4); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "uintBitsToFloat", uint4);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, uint1, "packSnorm2x16", float2);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, uint1, "packUnorm2x16", float2);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, uint1, "packHalf2x16", float2);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "unpackSnorm2x16", uint1);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "unpackUnorm2x16", uint1);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "unpackHalf2x16", uint1);
// //
// Geometric Functions. // Geometric Functions.
// //
...@@ -801,6 +808,14 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, ...@@ -801,6 +808,14 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
symbolTable.relateToOperator(ESSL3_BUILTINS, "intBitsToFloat", EOpIntBitsToFloat); symbolTable.relateToOperator(ESSL3_BUILTINS, "intBitsToFloat", EOpIntBitsToFloat);
symbolTable.relateToOperator(ESSL3_BUILTINS, "uintBitsToFloat", EOpUintBitsToFloat); symbolTable.relateToOperator(ESSL3_BUILTINS, "uintBitsToFloat", EOpUintBitsToFloat);
symbolTable.relateToOperator(ESSL3_BUILTINS, "packSnorm2x16", EOpPackSnorm2x16);
symbolTable.relateToOperator(ESSL3_BUILTINS, "packUnorm2x16", EOpPackUnorm2x16);
symbolTable.relateToOperator(ESSL3_BUILTINS, "packHalf2x16", EOpPackHalf2x16);
symbolTable.relateToOperator(ESSL3_BUILTINS, "unpackSnorm2x16", EOpUnpackSnorm2x16);
symbolTable.relateToOperator(ESSL3_BUILTINS, "unpackUnorm2x16", EOpUnpackUnorm2x16);
symbolTable.relateToOperator(ESSL3_BUILTINS, "unpackHalf2x16", EOpUnpackHalf2x16);
symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength); symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength);
symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance); symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance);
symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot); symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot);
......
...@@ -334,6 +334,9 @@ bool TIntermUnary::promote(TInfoSink &) ...@@ -334,6 +334,9 @@ bool TIntermUnary::promote(TInfoSink &)
case EOpVectorLogicalNot: case EOpVectorLogicalNot:
case EOpIntBitsToFloat: case EOpIntBitsToFloat:
case EOpUintBitsToFloat: case EOpUintBitsToFloat:
case EOpUnpackSnorm2x16:
case EOpUnpackUnorm2x16:
case EOpUnpackHalf2x16:
return true; return true;
default: default:
......
...@@ -135,6 +135,13 @@ enum TOperator ...@@ -135,6 +135,13 @@ enum TOperator
EOpIntBitsToFloat, EOpIntBitsToFloat,
EOpUintBitsToFloat, EOpUintBitsToFloat,
EOpPackSnorm2x16,
EOpPackUnorm2x16,
EOpPackHalf2x16,
EOpUnpackSnorm2x16,
EOpUnpackUnorm2x16,
EOpUnpackHalf2x16,
EOpLength, EOpLength,
EOpDistance, EOpDistance,
EOpDot, EOpDot,
......
...@@ -231,6 +231,22 @@ TIntermTyped *TIntermediate::addUnaryMath( ...@@ -231,6 +231,22 @@ TIntermTyped *TIntermediate::addUnaryMath(
if (!node->promote(mInfoSink)) if (!node->promote(mInfoSink))
return 0; return 0;
switch (op)
{
case EOpPackSnorm2x16:
case EOpPackUnorm2x16:
case EOpPackHalf2x16:
case EOpUnpackSnorm2x16:
case EOpUnpackUnorm2x16:
node->getTypePointer()->setPrecision(EbpHigh);
break;
case EOpUnpackHalf2x16:
node->getTypePointer()->setPrecision(EbpMedium);
break;
default:
break;
}
if (childTempConstant) if (childTempConstant)
{ {
TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink); TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink);
......
...@@ -499,6 +499,25 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) ...@@ -499,6 +499,25 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
preString = "uintBitsToFloat("; preString = "uintBitsToFloat(";
break; break;
case EOpPackSnorm2x16:
preString = "packSnorm2x16(";
break;
case EOpPackUnorm2x16:
preString = "packUnorm2x16(";
break;
case EOpPackHalf2x16:
preString = "packHalf2x16(";
break;
case EOpUnpackSnorm2x16:
preString = "unpackSnorm2x16(";
break;
case EOpUnpackUnorm2x16:
preString = "unpackUnorm2x16(";
break;
case EOpUnpackHalf2x16:
preString = "unpackHalf2x16(";
break;
case EOpLength: case EOpLength:
preString = "length("; preString = "length(";
break; break;
......
...@@ -1635,6 +1635,30 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) ...@@ -1635,6 +1635,30 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break; case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break;
case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
case EOpPackSnorm2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "packSnorm2x16(");
break;
case EOpPackUnorm2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "packUnorm2x16(");
break;
case EOpPackHalf2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "packHalf2x16(");
break;
case EOpUnpackSnorm2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "unpackSnorm2x16(");
break;
case EOpUnpackUnorm2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "unpackUnorm2x16(");
break;
case EOpUnpackHalf2x16:
ASSERT(node->getUseEmulatedFunction());
writeEmulatedFunctionTriplet(visit, "unpackHalf2x16(");
break;
case EOpLength: outputTriplet(visit, "length(", "", ")"); break; case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
case EOpDFdx: case EOpDFdx:
......
...@@ -302,6 +302,14 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) ...@@ -302,6 +302,14 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
case EOpIntBitsToFloat: out << "int bits to float"; break; case EOpIntBitsToFloat: out << "int bits to float"; break;
case EOpUintBitsToFloat: out << "uint bits to float"; break; case EOpUintBitsToFloat: out << "uint bits to float"; break;
case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break;
case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break;
case EOpPackHalf2x16: out << "pack half 2x16"; break;
case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break;
case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break;
case EOpUnpackHalf2x16: out << "unpack half 2x16"; break;
case EOpLength: out << "length"; break; case EOpLength: out << "length"; break;
case EOpNormalize: out << "normalize"; break; case EOpNormalize: out << "normalize"; break;
// case EOpDPdx: out << "dPdx"; break; // case EOpDPdx: out << "dPdx"; break;
......
...@@ -23,6 +23,7 @@ class TypeTrackingTest : public testing::Test ...@@ -23,6 +23,7 @@ class TypeTrackingTest : public testing::Test
{ {
ShBuiltInResources resources; ShBuiltInResources resources;
ShInitBuiltInResources(&resources); ShInitBuiltInResources(&resources);
resources.FragmentPrecisionHigh = 1;
mTranslator = new TranslatorESSL(GL_FRAGMENT_SHADER, SH_GLES3_SPEC); mTranslator = new TranslatorESSL(GL_FRAGMENT_SHADER, SH_GLES3_SPEC);
ASSERT_TRUE(mTranslator->Init(resources)); ASSERT_TRUE(mTranslator->Init(resources));
...@@ -263,3 +264,75 @@ TEST_F(TypeTrackingTest, StructConstructorResultNoPrecision) ...@@ -263,3 +264,75 @@ TEST_F(TypeTrackingTest, StructConstructorResultNoPrecision)
ASSERT_FALSE(foundErrorInIntermediateTree()); ASSERT_FALSE(foundErrorInIntermediateTree());
ASSERT_TRUE(foundInIntermediateTree("Construct structure (structure)")); ASSERT_TRUE(foundInIntermediateTree("Construct structure (structure)"));
}; };
TEST_F(TypeTrackingTest, PackResultTypeAndPrecision)
{
// ESSL 3.0 spec section 8.4: pack functions have predefined precision highp
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision mediump uint;\n"
"uniform vec2 uv;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" uint u0 = packSnorm2x16(uv);\n"
" uint u1 = packUnorm2x16(uv);\n"
" uint u2 = packHalf2x16(uv);\n"
" if (u0 + u1 + u2 > 100u) {\n"
" my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
" } else {\n"
" my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
" }\n"
"}\n";
compile(shaderString);
ASSERT_FALSE(foundErrorInIntermediateTree());
ASSERT_TRUE(foundInIntermediateTree("pack Snorm 2x16 (highp uint)"));
ASSERT_TRUE(foundInIntermediateTree("pack Unorm 2x16 (highp uint)"));
ASSERT_TRUE(foundInIntermediateTree("pack half 2x16 (highp uint)"));
};
TEST_F(TypeTrackingTest, UnpackNormResultTypeAndPrecision)
{
// ESSL 3.0 spec section 8.4: unpack(S/U)norm2x16 has predefined precision highp
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision mediump uint;\n"
"uniform uint uu;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" vec2 v0 = unpackSnorm2x16(uu);\n"
" vec2 v1 = unpackUnorm2x16(uu);\n"
" if (v0.x * v1.x > 1.0) {\n"
" my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
" } else {\n"
" my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
" }\n"
"}\n";
compile(shaderString);
ASSERT_FALSE(foundErrorInIntermediateTree());
ASSERT_TRUE(foundInIntermediateTree("unpack Snorm 2x16 (highp 2-component vector of float)"));
ASSERT_TRUE(foundInIntermediateTree("unpack Unorm 2x16 (highp 2-component vector of float)"));
};
TEST_F(TypeTrackingTest, UnpackHalfResultTypeAndPrecision)
{
// ESSL 3.0 spec section 8.4: unpackHalf2x16 has predefined precision mediump
const std::string &shaderString =
"#version 300 es\n"
"precision highp float;\n"
"precision highp uint;\n"
"uniform uint uu;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" vec2 v = unpackHalf2x16(uu);\n"
" if (v.x > 1.0) {\n"
" my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
" } else {\n"
" my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
" }\n"
"}\n";
compile(shaderString);
ASSERT_FALSE(foundErrorInIntermediateTree());
ASSERT_TRUE(foundInIntermediateTree("unpack half 2x16 (mediump 2-component vector of float)"));
};
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