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