// // 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 testSetUp() override { // Fragment Shader source constexpr char kSNormFS[] = R"(#version 300 es precision mediump float; uniform mediump vec2 v; layout(location = 0) out mediump vec4 fragColor; void main() { uint u = packSnorm2x16(v); vec2 r = unpackSnorm2x16(u); fragColor = vec4(r, 0.0, 1.0); })"; // Fragment Shader source constexpr char kUNormFS[] = R"(#version 300 es precision mediump float; uniform mediump vec2 v; layout(location = 0) out mediump vec4 fragColor; void main() { uint u = packUnorm2x16(v); vec2 r = unpackUnorm2x16(u); fragColor = vec4(r, 0.0, 1.0); })"; // Fragment Shader source constexpr char kHalfFS[] = R"(#version 300 es precision mediump float; uniform mediump vec2 v; layout(location = 0) out mediump vec4 fragColor; void main() { uint u = packHalf2x16(v); vec2 r = unpackHalf2x16(u); fragColor = vec4(r, 0.0, 1.0); })"; mSNormProgram = CompileProgram(essl3_shaders::vs::Simple(), kSNormFS); mUNormProgram = CompileProgram(essl3_shaders::vs::Simple(), kUNormFS); mHalfProgram = CompileProgram(essl3_shaders::vs::Simple(), kHalfFS); if (mSNormProgram == 0 || mUNormProgram == 0 || mHalfProgram == 0) { FAIL() << "shader compilation failed."; } glGenTextures(1, &mOffscreenTexture2D); glBindTexture(GL_TEXTURE_2D, mOffscreenTexture2D); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG32F, getWindowWidth(), getWindowHeight()); glGenFramebuffers(1, &mOffscreenFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mOffscreenTexture2D, 0); glViewport(0, 0, 16, 16); const GLfloat color[] = {1.0f, 1.0f, 0.0f, 1.0f}; glClearBufferfv(GL_COLOR, 0, color); } void testTearDown() override { glDeleteTextures(1, &mOffscreenTexture2D); glDeleteFramebuffers(1, &mOffscreenFramebuffer); glDeleteProgram(mSNormProgram); glDeleteProgram(mUNormProgram); glDeleteProgram(mHalfProgram); } void compareBeforeAfter(GLuint program, float input1, float input2) { compareBeforeAfter(program, input1, input2, input1, input2); } void compareBeforeAfter(GLuint program, float input1, float input2, float expect1, float expect2) { GLint vec2Location = glGetUniformLocation(program, "v"); glUseProgram(program); glUniform2f(vec2Location, input1, input2); drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); ASSERT_GL_NO_ERROR(); GLfloat p[2] = {0}; glReadPixels(8, 8, 1, 1, GL_RG, GL_FLOAT, p); ASSERT_GL_NO_ERROR(); static const double epsilon = 0.0005; EXPECT_NEAR(p[0], expect1, epsilon); EXPECT_NEAR(p[1], expect2, epsilon); } GLuint mSNormProgram; GLuint mUNormProgram; GLuint mHalfProgram; GLuint mOffscreenFramebuffer; GLuint mOffscreenTexture2D; }; // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating normal floating // numbers. TEST_P(PackUnpackTest, PackUnpackSnormNormal) { // Expect the shader to output the same value as the input 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 packSnorm2x16 and unpackSnorm2x16 functions calculating normal floating // numbers. TEST_P(PackUnpackTest, PackUnpackUnormNormal) { // Expect the shader to output the same value as the input compareBeforeAfter(mUNormProgram, 0.5f, 0.2f, 0.5f, 0.2f); compareBeforeAfter(mUNormProgram, 0.35f, 0.75f, 0.35f, 0.75f); compareBeforeAfter(mUNormProgram, 0.00392f, 0.99215f, 0.00392f, 0.99215f); compareBeforeAfter(mUNormProgram, 1.0f, 0.00392f, 1.0f, 0.00392f); } // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating normal floating // numbers. TEST_P(PackUnpackTest, PackUnpackHalfNormal) { // Expect the shader to output the same value as the input 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) { // Expect the shader to output the same value as the input compareBeforeAfter(mSNormProgram, 0.00001f, -0.00001f); } // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating subnormal // floating numbers. TEST_P(PackUnpackTest, PackUnpackUnormSubnormal) { // Expect the shader to output the same value as the input for positive numbers and clamp // to [0, 1] compareBeforeAfter(mUNormProgram, 0.00001f, -0.00001f, 0.00001f, 0.0f); } // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating subnormal floating // numbers. TEST_P(PackUnpackTest, PackUnpackHalfSubnormal) { // Expect the shader to output the same value as the input compareBeforeAfter(mHalfProgram, 0.00001f, -0.00001f); } // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating zero floating // numbers. TEST_P(PackUnpackTest, PackUnpackSnormZero) { // Expect the shader to output the same value as the input compareBeforeAfter(mSNormProgram, 0.00000f, -0.00000f); } // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating zero floating // numbers. TEST_P(PackUnpackTest, PackUnpackUnormZero) { compareBeforeAfter(mUNormProgram, 0.00000f, -0.00000f, 0.00000f, 0.00000f); } // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating zero floating // numbers. TEST_P(PackUnpackTest, PackUnpackHalfZero) { // Expect the shader to output the same value as the input compareBeforeAfter(mHalfProgram, 0.00000f, -0.00000f); } // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating overflow floating // numbers. TEST_P(PackUnpackTest, PackUnpackUnormOverflow) { // Expect the shader to clamp the input to [0, 1] compareBeforeAfter(mUNormProgram, 67000.0f, -67000.0f, 1.0f, 0.0f); } // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating overflow floating // numbers. TEST_P(PackUnpackTest, PackUnpackSnormOverflow) { // Expect the shader to clamp the input to [-1, 1] compareBeforeAfter(mSNormProgram, 67000.0f, -67000.0f, 1.0f, -1.0f); } ANGLE_INSTANTIATE_TEST(PackUnpackTest, ES3_OPENGL(), ES3_OPENGLES()); // http://anglebug.com/4092 Not instantiating on other backends currently } // namespace