Commit 03f3caec by Qingqing Deng Committed by Olli Etuaho

Emulate Missing pack_unpack functions from OpenGL 4.1

BUG=angleproject:947 TEST=angle_unittests, angle_end2end_tests Change-Id: Id1afd7630d9720b6701225b7abf1ce4a3bf528b6 Reviewed-on: https://chromium-review.googlesource.com/260232Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent a4aa4e30
...@@ -35,3 +35,73 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum ...@@ -35,3 +35,73 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum
emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))"); emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))"); emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
} }
// emulate built-in functions missing from OpenGL 4.1
void InitBuiltInFunctionEmulatorForGLSL4_1(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
{
TType *float2 = new TType(EbtFloat, 2);
TType *uint1 = new TType(EbtUInt);
emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
"uint webgl_packSnorm2x16_emu(vec2 v){\n"
" int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
" int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
" return uint((y << 16) | (x & 0xffff));\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(uint x){\n"
" int xi = (int(x) & 0x7fff) - (int(x) & 0x8000);\n"
" return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
"}\n"
"vec2 webgl_unpackSnorm2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u;\n"
" return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
"}\n");
// Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
// based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
emu->addEmulatedFunction(EOpPackHalf2x16, float2,
"uint webgl_f32tof16(float val){\n"
" uint f32 = floatBitsToInt(val);\n"
" uint f16 = 0;\n"
" uint sign = (f32 >> 16) & 0x8000u;\n"
" int exponent = int((f32 >> 23) & 0xff) - 127;\n"
" uint mantissa = f32 & 0x007fffffu;\n"
" if (exponent == 128) { /* Infinity or NaN */\n"
" // NaN bits that are masked out by 0x3ff get discarded. This can turn some NaNs to infinity, but this is allowed by the spec.\n"
" f16 = sign | (0x1F << 10); f16 |= (mantissa & 0x3ff);\n"
" }\n"
" else if (exponent > 15) { /* Overflow - flush to Infinity */ f16 = sign | (0x1F << 10); }\n"
" else if (exponent > -15) { /* Representable value */ exponent += 15; mantissa >>= 13; f16 = sign | exponent << 10 | mantissa; }\n"
" else { f16 = sign; }\n"
" return f16;\n"
"}\n"
"uint webgl_packHalf2x16_emu(vec2 v){\n"
" uint x = webgl_f32tof16(v.x);\n"
" uint y = webgl_f32tof16(v.y);\n"
" return (y << 16) | x;\n"
"}\n");
emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
"float webgl_f16tof32(uint val){\n"
" uint sign = (val & 0x8000u) << 16;\n"
" int exponent = int((val & 0x7c00) >> 10);\n"
" uint mantissa = val & 0x03ffu;\n"
" float f32 = 0.0;\n"
" if(exponent == 0) { if (mantissa != 0) { const float scale = 1.0 / (1 << 24); f32 = scale * mantissa; } }\n"
" else if (exponent == 31) { return uintBitsToFloat(sign | 0x7f800000 | mantissa); }\n"
" else{\n"
" float scale, decimal; exponent -= 15;\n"
" if(exponent < 0) { scale = 1.0 / (1 << -exponent); }\n"
" else { scale = 1 << exponent; }\n"
" decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
" f32 = scale * decimal;\n"
" }\n"
" if (sign != 0) f32 = -f32;\n"
" return f32;\n"
"}\n"
"vec2 webgl_unpackHalf2x16_emu(uint u){\n"
" uint y = (u >> 16);\n"
" uint x = u & 0xffffu;\n"
" return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
"}\n");
}
\ No newline at end of file
...@@ -16,4 +16,9 @@ class BuiltInFunctionEmulator; ...@@ -16,4 +16,9 @@ class BuiltInFunctionEmulator;
// //
void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType); void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
//
// This function is emulating built-in functions missing from OpenGL 4.1.
//
void InitBuiltInFunctionEmulatorForGLSL4_1(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ #endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
...@@ -67,6 +67,8 @@ void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, i ...@@ -67,6 +67,8 @@ void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, i
{ {
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
if (getOutputType() == SH_GLSL_410_CORE_OUTPUT)
InitBuiltInFunctionEmulatorForGLSL4_1(emu, getShaderType());
} }
void TranslatorGLSL::translate(TIntermNode *root, int) { void TranslatorGLSL::translate(TIntermNode *root, int) {
......
...@@ -21,7 +21,7 @@ static size_t activeCompilerHandles = 0; ...@@ -21,7 +21,7 @@ static size_t activeCompilerHandles = 0;
CompilerGL::CompilerGL(const gl::Data &data) CompilerGL::CompilerGL(const gl::Data &data)
: CompilerImpl(), : CompilerImpl(),
mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC), mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC),
mOutputType(SH_GLSL_OUTPUT), mOutputType(data.clientVersion > 2 ? SH_GLSL_410_CORE_OUTPUT : SH_GLSL_OUTPUT),
mResources(), mResources(),
mFragmentCompiler(nullptr), mFragmentCompiler(nullptr),
mVertexCompiler(nullptr) mVertexCompiler(nullptr)
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
'<(angle_path)/src/tests/gl_tests/MaxTextureSizeTest.cpp', '<(angle_path)/src/tests/gl_tests/MaxTextureSizeTest.cpp',
'<(angle_path)/src/tests/gl_tests/MipmapTest.cpp', '<(angle_path)/src/tests/gl_tests/MipmapTest.cpp',
'<(angle_path)/src/tests/gl_tests/media/pixel.inl', '<(angle_path)/src/tests/gl_tests/media/pixel.inl',
'<(angle_path)/src/tests/gl_tests/PackUnpackTest.cpp',
'<(angle_path)/src/tests/gl_tests/PbufferTest.cpp', '<(angle_path)/src/tests/gl_tests/PbufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/PBOExtensionTest.cpp', '<(angle_path)/src/tests/gl_tests/PBOExtensionTest.cpp',
'<(angle_path)/src/tests/gl_tests/PointSpritesTest.cpp', '<(angle_path)/src/tests/gl_tests/PointSpritesTest.cpp',
......
# Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. # Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
'<(angle_path)/src/tests/compiler_tests/ExpressionLimit_test.cpp', '<(angle_path)/src/tests/compiler_tests/ExpressionLimit_test.cpp',
'<(angle_path)/src/tests/compiler_tests/MalformedShader_test.cpp', '<(angle_path)/src/tests/compiler_tests/MalformedShader_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp', '<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
'<(angle_path)/src/tests/compiler_tests/Pack_Unpack_test.cpp',
'<(angle_path)/src/tests/compiler_tests/PruneUnusedFunctions_test.cpp', '<(angle_path)/src/tests/compiler_tests/PruneUnusedFunctions_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp', '<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RemovePow_test.cpp', '<(angle_path)/src/tests/compiler_tests/RemovePow_test.cpp',
......
//
// Copyright (c) 2015 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.
//
// Pack_Unpack_test.cpp:
// Tests for the emulating pack_unpack functions for GLSL 4.1.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/TranslatorGLSL.h"
namespace
{
class PackUnpackTest : public testing::Test
{
public:
PackUnpackTest() {}
protected:
void SetUp() override
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
mTranslator = new TranslatorGLSL(
GL_FRAGMENT_SHADER, SH_GLES3_SPEC, SH_GLSL_410_CORE_OUTPUT);
ASSERT_TRUE(mTranslator->Init(resources));
}
void TearDown() override
{
SafeDelete(mTranslator);
}
void compile(const std::string& shaderString)
{
const char *shaderStrings[] = { shaderString.c_str() };
bool compilationSuccess = mTranslator->compile(shaderStrings, 1, SH_OBJECT_CODE);
TInfoSink &infoSink = mTranslator->getInfoSink();
mGLSLCode = infoSink.obj.c_str();
if (!compilationSuccess)
{
FAIL() << "Shader compilation into GLSL 4.1 failed " << infoSink.info.c_str();
}
}
bool foundInGLSLCode(const char* stringToFind)
{
return mGLSLCode.find(stringToFind) != std::string::npos;
}
private:
TranslatorGLSL *mTranslator;
std::string mGLSLCode;
};
//Check if PackSnorm2x16 Emulation for GLSL 4.1 compile correctly.
TEST_F(PackUnpackTest, PackSnorm2x16Emulation)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;"
"void main() {\n"
" vec2 v;\n"
" uint u = packSnorm2x16(v);\n"
" fragColor = vec4(0.0);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(foundInGLSLCode("uint webgl_packSnorm2x16_emu(vec2 v)"));
}
//Check if UnpackSnorm2x16 Emulation for GLSL 4.1 compile correctly.
TEST_F(PackUnpackTest, UnpackSnorm2x16Emulation)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;"
"void main() {\n"
" uint u;\n"
" vec2 v=unpackSnorm2x16(u);\n"
" fragColor = vec4(0.0);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(foundInGLSLCode("vec2 webgl_unpackSnorm2x16_emu(uint u)"));
}
//Check if PackHalf2x16 Emulation for GLSL 4.1 compile correctly.
TEST_F(PackUnpackTest, PackHalf2x16Emulation)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;"
"void main() {\n"
" vec2 v;\n"
" uint u=packHalf2x16(v);\n"
" fragColor = vec4(0.0);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(foundInGLSLCode("uint webgl_packHalf2x16_emu(vec2 v)"));
}
//Check if UnpackHalf2x16 Emulation for GLSL 4.1 compile correctly.
TEST_F(PackUnpackTest, UnpackHalf2x16Emulation)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;"
"void main() {\n"
" uint u;\n"
" vec2 v=unpackHalf2x16(u);\n"
" fragColor = vec4(0.0);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(foundInGLSLCode("vec2 webgl_unpackHalf2x16_emu(uint u)"));
}
}
\ No newline at end of file
# Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. # Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
'ExpressionLimit_test.cpp', 'ExpressionLimit_test.cpp',
'MalformedShader_test.cpp', 'MalformedShader_test.cpp',
'NV_draw_buffers_test.cpp', 'NV_draw_buffers_test.cpp',
'Pack_Unpack_test.cpp',
'PruneUnusedFunctions_test.cpp', 'PruneUnusedFunctions_test.cpp',
'RecordConstantPrecision_test.cpp', 'RecordConstantPrecision_test.cpp',
'RemovePow_test.cpp', 'RemovePow_test.cpp',
......
//
// Copyright 2015 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.
//
// PackUnpackTest:
// Tests the corrrectness of opengl 4.1 emulation of pack/unpack built-in functions.
//
#include "test_utils/ANGLETest.h"
using namespace angle;
namespace
{
class PackUnpackTest : public ANGLETest
{
protected:
PackUnpackTest()
{
setWindowWidth(16);
setWindowHeight(16);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void SetUp() override
{
ANGLETest::SetUp();
// Vertex Shader source
const std::string vs = SHADER_SOURCE
( #version 300 es\n
precision mediump float;
in vec4 position;
void main()
{
gl_Position = position;
}
);
// Fragment Shader source
const std::string sNormFS = SHADER_SOURCE
( #version 300 es\n
precision mediump float;
uniform mediump vec2 v;
layout(location = 0) out mediump vec4 fragColor;
void main()
{
uint u = packSnorm2x16(v);
vec2 r = unpackSnorm2x16(u);
if (r.x < 0.0) r.x = 1.0 + r.x;
if (r.y < 0.0) r.y = 1.0 + r.y;
fragColor = vec4(r, 0.0, 1.0);
}
);
// Fragment Shader source
const std::string halfFS = SHADER_SOURCE
( #version 300 es\n
precision mediump float;
uniform mediump vec2 v;
layout(location = 0) out mediump vec4 fragColor;
void main()
{
uint u = packHalf2x16(v);
vec2 r = unpackHalf2x16(u);
if (r.x < 0.0) r.x = 1.0 + r.x;
if (r.y < 0.0) r.y = 1.0 + r.y;
fragColor = vec4(r, 0.0, 1.0);
}
);
mSNormProgram = CompileProgram(vs, sNormFS);
mHalfProgram = CompileProgram(vs, halfFS);
if (mSNormProgram == 0 || mHalfProgram == 0)
{
FAIL() << "shader compilation failed.";
}
glGenFramebuffers(1, &mOffscreenFramebuffer);
glGenTextures(1, &mOffscreenTexture2D);
}
void TearDown() override
{
glDeleteTextures(1, &mOffscreenTexture2D);
glDeleteFramebuffers(1, &mOffscreenFramebuffer);
glDeleteProgram(mSNormProgram);
glDeleteProgram(mHalfProgram);
ANGLETest::TearDown();
}
double computeOutput(float input)
{
if (input <= -1.0)
return 0;
else if (input >= 1.0)
return 255;
else if (input < -6.10E-05 && input > -1.0)
return 255 * (1.0 + input);
else
return 255 * input;
}
void compareBeforeAfter(GLuint program, float input1, float input2)
{
glBindTexture(GL_TEXTURE_2D, mOffscreenTexture2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mOffscreenTexture2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
glViewport(0, 0, 16, 16);
const GLfloat color[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
GLfloat vertexLocations[] =
{
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
};
GLint positionLocation = glGetAttribLocation(program, "position");
GLint vec2Location = glGetUniformLocation(program, "v");
glUseProgram(program);
glUniform2f(vec2Location, input1, input2);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertexLocations);
glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glUseProgram(0);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(8, 8, computeOutput(input1), computeOutput(input2), 0, 255, 1.0);
}
GLuint mSNormProgram;
GLuint mHalfProgram;
GLuint mOffscreenFramebuffer;
GLuint mOffscreenTexture2D;
};
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating normal floating numbers.
TEST_P(PackUnpackTest, PackUnpackSnormNormal)
{
compareBeforeAfter(mSNormProgram, 0.5f, -0.2f);
compareBeforeAfter(mSNormProgram, -0.35f, 0.75f);
compareBeforeAfter(mSNormProgram, 0.00392f, -0.99215f);
compareBeforeAfter(mSNormProgram, 1.0f, -0.00392f);
}
// Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating normal floating numbers.
TEST_P(PackUnpackTest, PackUnpackHalfNormal)
{
compareBeforeAfter(mHalfProgram, 0.5f, -0.2f);
compareBeforeAfter(mHalfProgram, -0.35f, 0.75f);
compareBeforeAfter(mHalfProgram, 0.00392f, -0.99215f);
compareBeforeAfter(mHalfProgram, 1.0f, -0.00392f);
}
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating subnormal floating numbers.
TEST_P(PackUnpackTest, PackUnpackSnormSubnormal)
{
compareBeforeAfter(mSNormProgram, 0.00001f, -0.00001f);
}
// Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating subnormal floating numbers.
TEST_P(PackUnpackTest, PackUnpackHalfSubnormal)
{
compareBeforeAfter(mHalfProgram, 0.00001f, -0.00001f);
}
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating zero floating numbers.
TEST_P(PackUnpackTest, PackUnpackSnormZero)
{
compareBeforeAfter(mSNormProgram, 0.00000f, -0.00000f);
}
// Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating zero floating numbers.
TEST_P(PackUnpackTest, PackUnpackHalfZero)
{
compareBeforeAfter(mHalfProgram, 0.00000f, -0.00000f);
}
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating overflow floating numbers.
TEST_P(PackUnpackTest, PackUnpackSnormOverflow)
{
compareBeforeAfter(mHalfProgram, 67000.0f, -67000.0f);
}
// Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating overflow floating numbers.
TEST_P(PackUnpackTest, PackUnpackHalfOverflow)
{
compareBeforeAfter(mHalfProgram, 67000.0f, -67000.0f);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(PackUnpackTest, ES3_OPENGL());
}
\ No newline at end of file
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