1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // PackUnpackTest:
7 // Tests the corrrectness of opengl 4.1 emulation of pack/unpack built-in functions.
8 //
9
10 #include "test_utils/ANGLETest.h"
11
12 using namespace angle;
13
14 namespace
15 {
16
17 class PackUnpackTest : public ANGLETest
18 {
19 protected:
PackUnpackTest()20 PackUnpackTest()
21 {
22 setWindowWidth(16);
23 setWindowHeight(16);
24 setConfigRedBits(8);
25 setConfigGreenBits(8);
26 setConfigBlueBits(8);
27 setConfigAlphaBits(8);
28 }
29
SetUp()30 void SetUp() override
31 {
32 ANGLETest::SetUp();
33
34 // Vertex Shader source
35 const std::string vs = SHADER_SOURCE
36 ( #version 300 es\n
37 precision mediump float;
38 in vec4 position;
39
40 void main()
41 {
42 gl_Position = position;
43 }
44 );
45
46 // clang-format off
47 // Fragment Shader source
48 const std::string sNormFS = SHADER_SOURCE
49 ( #version 300 es\n
50 precision mediump float;
51 uniform mediump vec2 v;
52 layout(location = 0) out mediump vec4 fragColor;
53
54 void main()
55 {
56 uint u = packSnorm2x16(v);
57 vec2 r = unpackSnorm2x16(u);
58 fragColor = vec4(r, 0.0, 1.0);
59 }
60 );
61
62 // Fragment Shader source
63 const std::string uNormFS = SHADER_SOURCE
64 ( #version 300 es\n
65 precision mediump float;
66 uniform mediump vec2 v;
67 layout(location = 0) out mediump vec4 fragColor;
68
69 void main()
70 {
71 uint u = packUnorm2x16(v);
72 vec2 r = unpackUnorm2x16(u);
73 fragColor = vec4(r, 0.0, 1.0);
74 }
75 );
76
77 // Fragment Shader source
78 const std::string halfFS = SHADER_SOURCE
79 ( #version 300 es\n
80 precision mediump float;
81 uniform mediump vec2 v;
82 layout(location = 0) out mediump vec4 fragColor;
83
84 void main()
85 {
86 uint u = packHalf2x16(v);
87 vec2 r = unpackHalf2x16(u);
88 fragColor = vec4(r, 0.0, 1.0);
89 }
90 );
91 // clang-format on
92
93 mSNormProgram = CompileProgram(vs, sNormFS);
94 mUNormProgram = CompileProgram(vs, uNormFS);
95 mHalfProgram = CompileProgram(vs, halfFS);
96 if (mSNormProgram == 0 || mUNormProgram == 0 || mHalfProgram == 0)
97 {
98 FAIL() << "shader compilation failed.";
99 }
100
101 glGenTextures(1, &mOffscreenTexture2D);
102 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture2D);
103 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG32F, getWindowWidth(), getWindowHeight());
104
105 glGenFramebuffers(1, &mOffscreenFramebuffer);
106 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
107 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mOffscreenTexture2D, 0);
108
109 glViewport(0, 0, 16, 16);
110
111 const GLfloat color[] = { 1.0f, 1.0f, 0.0f, 1.0f };
112 glClearBufferfv(GL_COLOR, 0, color);
113 }
114
TearDown()115 void TearDown() override
116 {
117 glDeleteTextures(1, &mOffscreenTexture2D);
118 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
119 glDeleteProgram(mSNormProgram);
120 glDeleteProgram(mUNormProgram);
121 glDeleteProgram(mHalfProgram);
122
123 ANGLETest::TearDown();
124 }
125
compareBeforeAfter(GLuint program,float input1,float input2)126 void compareBeforeAfter(GLuint program, float input1, float input2)
127 {
128 compareBeforeAfter(program, input1, input2, input1, input2);
129 }
130
compareBeforeAfter(GLuint program,float input1,float input2,float expect1,float expect2)131 void compareBeforeAfter(GLuint program, float input1, float input2, float expect1, float expect2)
132 {
133 GLint vec2Location = glGetUniformLocation(program, "v");
134
135 glUseProgram(program);
136 glUniform2f(vec2Location, input1, input2);
137
138 drawQuad(program, "position", 0.5f);
139
140 ASSERT_GL_NO_ERROR();
141
142 GLfloat p[2] = { 0 };
143 glReadPixels(8, 8, 1, 1, GL_RG, GL_FLOAT, p);
144
145 ASSERT_GL_NO_ERROR();
146
147 static const double epsilon = 0.0005;
148 EXPECT_NEAR(p[0], expect1, epsilon);
149 EXPECT_NEAR(p[1], expect2, epsilon);
150 }
151
152 GLuint mSNormProgram;
153 GLuint mUNormProgram;
154 GLuint mHalfProgram;
155 GLuint mOffscreenFramebuffer;
156 GLuint mOffscreenTexture2D;
157 };
158
159 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating normal floating numbers.
TEST_P(PackUnpackTest,PackUnpackSnormNormal)160 TEST_P(PackUnpackTest, PackUnpackSnormNormal)
161 {
162 // Expect the shader to output the same value as the input
163 compareBeforeAfter(mSNormProgram, 0.5f, -0.2f);
164 compareBeforeAfter(mSNormProgram, -0.35f, 0.75f);
165 compareBeforeAfter(mSNormProgram, 0.00392f, -0.99215f);
166 compareBeforeAfter(mSNormProgram, 1.0f, -0.00392f);
167 }
168
169 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating normal floating
170 // numbers.
TEST_P(PackUnpackTest,PackUnpackUnormNormal)171 TEST_P(PackUnpackTest, PackUnpackUnormNormal)
172 {
173 // Expect the shader to output the same value as the input
174 compareBeforeAfter(mUNormProgram, 0.5f, 0.2f, 0.5f, 0.2f);
175 compareBeforeAfter(mUNormProgram, 0.35f, 0.75f, 0.35f, 0.75f);
176 compareBeforeAfter(mUNormProgram, 0.00392f, 0.99215f, 0.00392f, 0.99215f);
177 compareBeforeAfter(mUNormProgram, 1.0f, 0.00392f, 1.0f, 0.00392f);
178 }
179
180 // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating normal floating numbers.
TEST_P(PackUnpackTest,PackUnpackHalfNormal)181 TEST_P(PackUnpackTest, PackUnpackHalfNormal)
182 {
183 // TODO(cwallez) figure out why it is broken on Intel on Mac
184 #if defined(ANGLE_PLATFORM_APPLE)
185 if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
186 {
187 std::cout << "Test skipped on Intel on Mac." << std::endl;
188 return;
189 }
190 #endif
191
192 // Expect the shader to output the same value as the input
193 compareBeforeAfter(mHalfProgram, 0.5f, -0.2f);
194 compareBeforeAfter(mHalfProgram, -0.35f, 0.75f);
195 compareBeforeAfter(mHalfProgram, 0.00392f, -0.99215f);
196 compareBeforeAfter(mHalfProgram, 1.0f, -0.00392f);
197 }
198
199 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating subnormal floating numbers.
TEST_P(PackUnpackTest,PackUnpackSnormSubnormal)200 TEST_P(PackUnpackTest, PackUnpackSnormSubnormal)
201 {
202 // Expect the shader to output the same value as the input
203 compareBeforeAfter(mSNormProgram, 0.00001f, -0.00001f);
204 }
205
206 // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating subnormal
207 // floating numbers.
TEST_P(PackUnpackTest,PackUnpackUnormSubnormal)208 TEST_P(PackUnpackTest, PackUnpackUnormSubnormal)
209 {
210 // Expect the shader to output the same value as the input for positive numbers and clamp
211 // to [0, 1]
212 compareBeforeAfter(mUNormProgram, 0.00001f, -0.00001f, 0.00001f, 0.0f);
213 }
214
215 // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating subnormal floating numbers.
TEST_P(PackUnpackTest,PackUnpackHalfSubnormal)216 TEST_P(PackUnpackTest, PackUnpackHalfSubnormal)
217 {
218 // Expect the shader to output the same value as the input
219 compareBeforeAfter(mHalfProgram, 0.00001f, -0.00001f);
220 }
221
222 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating zero floating numbers.
TEST_P(PackUnpackTest,PackUnpackSnormZero)223 TEST_P(PackUnpackTest, PackUnpackSnormZero)
224 {
225 // Expect the shader to output the same value as the input
226 compareBeforeAfter(mSNormProgram, 0.00000f, -0.00000f);
227 }
228
229 // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating zero floating
230 // numbers.
TEST_P(PackUnpackTest,PackUnpackUnormZero)231 TEST_P(PackUnpackTest, PackUnpackUnormZero)
232 {
233 compareBeforeAfter(mUNormProgram, 0.00000f, -0.00000f, 0.00000f, 0.00000f);
234 }
235
236 // Test the correctness of packHalf2x16 and unpackHalf2x16 functions calculating zero floating numbers.
TEST_P(PackUnpackTest,PackUnpackHalfZero)237 TEST_P(PackUnpackTest, PackUnpackHalfZero)
238 {
239 // Expect the shader to output the same value as the input
240 compareBeforeAfter(mHalfProgram, 0.00000f, -0.00000f);
241 }
242
243 // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions calculating overflow floating
244 // numbers.
TEST_P(PackUnpackTest,PackUnpackUnormOverflow)245 TEST_P(PackUnpackTest, PackUnpackUnormOverflow)
246 {
247 // Expect the shader to clamp the input to [0, 1]
248 compareBeforeAfter(mUNormProgram, 67000.0f, -67000.0f, 1.0f, 0.0f);
249 }
250
251 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions calculating overflow floating numbers.
TEST_P(PackUnpackTest,PackUnpackSnormOverflow)252 TEST_P(PackUnpackTest, PackUnpackSnormOverflow)
253 {
254 // Expect the shader to clamp the input to [-1, 1]
255 compareBeforeAfter(mSNormProgram, 67000.0f, -67000.0f, 1.0f, -1.0f);
256 }
257
258 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
259 ANGLE_INSTANTIATE_TEST(PackUnpackTest,
260 ES3_OPENGL(3, 3),
261 ES3_OPENGL(4, 0),
262 ES3_OPENGL(4, 1),
263 ES3_OPENGL(4, 2),
264 ES3_OPENGL(4, 3),
265 ES3_OPENGL(4, 4),
266 ES3_OPENGL(4, 5),
267 ES3_OPENGLES());
268 }
269