1 //
2 // Copyright 2020 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 // Tests for shader interpolation qualifiers
7 //
8 
9 #include "common/mathutil.h"
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12 
13 using namespace angle;
14 
15 constexpr int kPixelColorThreshhold = 8;
16 
17 class ShaderInterpTest : public ANGLETest
18 {
19   protected:
ShaderInterpTest()20     ShaderInterpTest() : ANGLETest()
21     {
22         setWindowWidth(128);
23         setWindowHeight(128);
24     }
25 
draw(GLuint program,float skew)26     void draw(GLuint program, float skew)
27     {
28         glUseProgram(program);
29 
30         std::array<Vector4, 3> vertices;
31         vertices[0] = {-1.0, -1.0, 0.0, 1.0};
32         vertices[1] = {1.0, -1.0, 0.0, 1.0};
33         vertices[2] = {0.0, 1.0 * skew, 0.0, skew};
34 
35         std::array<Vector4, 3> colors;
36         colors[0] = {1.0, 0.0, 0.0, 1.0};
37         colors[1] = {0.0, 1.0, 0.0, 1.0};
38         colors[2] = {0.0, 0.0, 1.0, 1.0};
39 
40         GLint positionLocation = glGetAttribLocation(program, "position");
41         GLint colorLocation    = glGetAttribLocation(program, "vertex_color");
42 
43         glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, vertices.data());
44         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.data());
45 
46         glEnableVertexAttribArray(positionLocation);
47         glEnableVertexAttribArray(colorLocation);
48 
49         glDrawArrays(GL_TRIANGLES, 0, 3);
50     }
51 };
52 
53 // Test that regular "smooth" interpolation works correctly
TEST_P(ShaderInterpTest,Smooth)54 TEST_P(ShaderInterpTest, Smooth)
55 {
56     const char *vertSrc = R"(#version 300 es
57 precision highp float;
58 in vec4 position;
59 in vec4 vertex_color;
60 smooth out vec4 interp_color;
61 
62 void main()
63 {
64     gl_Position = position;
65     interp_color = vertex_color;
66 }
67 )";
68     const char *fragSrc = R"(#version 300 es
69 precision highp float;
70 smooth in vec4 interp_color;
71 out vec4 fragColor;
72 
73 void main()
74 {
75     fragColor = interp_color;
76 }
77 )";
78 
79     // iOS chokes on the "smooth" qualifier.
80     // TODO(anglebug.com/5491): Add shader compiler workaround that omits "smooth".
81     ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
82 
83     ANGLE_GL_PROGRAM(program, vertSrc, fragSrc);
84     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
85 
86     glClear(GL_COLOR_BUFFER_BIT);
87     draw(program, 1.0);
88     EXPECT_PIXEL_COLOR_NEAR(64, 64, GLColor(62, 64, 128, 255), kPixelColorThreshhold);
89 
90     glClear(GL_COLOR_BUFFER_BIT);
91     draw(program, 2.0);
92     EXPECT_PIXEL_COLOR_NEAR(64, 64, GLColor(83, 86, 86, 255), kPixelColorThreshhold);
93 }
94 
95 // Test that uninterpolated "Flat" interpolation works correctly
TEST_P(ShaderInterpTest,Flat)96 TEST_P(ShaderInterpTest, Flat)
97 {
98     // TODO: anglebug.com/4085
99     // No vendors currently support VK_EXT_provoking_vertex, which is necessary for conformant flat
100     // shading. SwiftShader does technically support this extension, but as it has not yet been
101     // ratified by Khronos, the vulkan validation layers do not recognize the create info struct,
102     // causing it to be stripped and thus causing the extension to behave as if it is disabled.
103     ANGLE_SKIP_TEST_IF(IsVulkan());
104 
105     // http://anglebug.com/5232. Metal doesn't support last provoking vertex yet.
106     ANGLE_SKIP_TEST_IF(IsMetal());
107 
108     const char *vertSrc = R"(#version 300 es
109 precision highp float;
110 in vec4 position;
111 in vec4 vertex_color;
112 flat out vec4 interp_color;
113 
114 void main()
115 {
116     gl_Position = position;
117     interp_color = vertex_color;
118 }
119 )";
120     const char *fragSrc = R"(#version 300 es
121 precision highp float;
122 flat in vec4 interp_color;
123 out vec4 fragColor;
124 
125 void main()
126 {
127     fragColor = interp_color;
128 }
129 )";
130 
131     ANGLE_GL_PROGRAM(program, vertSrc, fragSrc);
132     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
133 
134     glClear(GL_COLOR_BUFFER_BIT);
135     draw(program, 1.0);
136     GLColor smooth_reference;
137     glReadPixels(64, 64, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &smooth_reference);
138     EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor(0, 0, 255, 255));
139 }
140 
141 // Test that "noperspective" interpolation correctly interpolates in screenspace
TEST_P(ShaderInterpTest,NoPerspective)142 TEST_P(ShaderInterpTest, NoPerspective)
143 {
144     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_shader_noperspective_interpolation"));
145 
146     const char *vertSrcSmooth = R"(#version 300 es
147 precision highp float;
148 in vec4 position;
149 in vec4 vertex_color;
150 smooth out vec4 interp_color;
151 
152 void main()
153 {
154     gl_Position = position;
155     interp_color = vertex_color;
156 }
157 )";
158     const char *fragSrcSmooth = R"(#version 300 es
159 precision highp float;
160 smooth in vec4 interp_color;
161 out vec4 fragColor;
162 
163 void main()
164 {
165     fragColor = interp_color;
166 }
167 )";
168     ANGLE_GL_PROGRAM(programSmooth, vertSrcSmooth, fragSrcSmooth);
169     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
170     glClear(GL_COLOR_BUFFER_BIT);
171     draw(programSmooth, 1.0);
172     GLColor smooth_reference;
173     glReadPixels(64, 64, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &smooth_reference);
174 
175     const char *vertSrcNoPerspective = R"(#version 300 es
176 #extension GL_NV_shader_noperspective_interpolation : require
177 
178 #ifndef GL_NV_shader_noperspective_interpolation
179 #error GL_NV_shader_noperspective_interpolation is not defined
180 #endif
181 
182 precision highp float;
183 in vec4 position;
184 in vec4 vertex_color;
185 noperspective out vec4 interp_color;
186 
187 void main()
188 {
189     gl_Position = position;
190     interp_color = vertex_color;
191 }
192 )";
193     const char *fragSrcNoPerspective = R"(#version 300 es
194 #extension GL_NV_shader_noperspective_interpolation : require
195 
196 #ifndef GL_NV_shader_noperspective_interpolation
197 #error GL_NV_shader_noperspective_interpolation is not defined
198 #endif
199 
200 precision highp float;
201 noperspective in vec4 interp_color;
202 out vec4 fragColor;
203 
204 void main()
205 {
206     fragColor = interp_color;
207 }
208 )";
209     ANGLE_GL_PROGRAM(programNoPerspective, vertSrcNoPerspective, fragSrcNoPerspective);
210     glClear(GL_COLOR_BUFFER_BIT);
211     draw(programNoPerspective, 1.0);
212     EXPECT_PIXEL_COLOR_EQ(64, 64, smooth_reference);
213 
214     glClear(GL_COLOR_BUFFER_BIT);
215     draw(programNoPerspective, 2.0);
216     EXPECT_PIXEL_COLOR_EQ(64, 64, smooth_reference);
217 }
218 
219 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShaderInterpTest);
220 ANGLE_INSTANTIATE_TEST_ES3(ShaderInterpTest);