1 //
2 // Copyright 2023 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 // Test state requests and compilation of tokens added by OES_shader_multisample_interpolation
7
8 #include "common/mathutil.h"
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 using namespace angle;
13
14 namespace
15 {
16
17 class SampleMultisampleInterpolationTest : public ANGLETest<>
18 {
19 protected:
SampleMultisampleInterpolationTest()20 SampleMultisampleInterpolationTest()
21 {
22 setConfigRedBits(8);
23 setConfigGreenBits(8);
24 setConfigBlueBits(8);
25 setConfigAlphaBits(8);
26 setExtensionsEnabled(false);
27 }
28 };
29
30 // Test state queries
TEST_P(SampleMultisampleInterpolationTest,StateQueries)31 TEST_P(SampleMultisampleInterpolationTest, StateQueries)
32 {
33 // New state queries fail without the extension
34 {
35 GLint bits = 0;
36 glGetIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES, &bits);
37 EXPECT_GL_ERROR(GL_INVALID_ENUM);
38 EXPECT_EQ(bits, 0);
39
40 GLfloat minOffset = 0.0f;
41 glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES, &minOffset);
42 EXPECT_GL_ERROR(GL_INVALID_ENUM);
43 EXPECT_EQ(minOffset, 0.0f);
44
45 GLfloat maxOffset = 0.0f;
46 glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES, &maxOffset);
47 EXPECT_GL_ERROR(GL_INVALID_ENUM);
48 EXPECT_EQ(maxOffset, 0.0f);
49
50 ASSERT_GL_NO_ERROR();
51 }
52
53 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
54
55 // Implementation-dependent values
56 {
57 GLint bits = 0;
58 glGetIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES, &bits);
59 EXPECT_GE(bits, 4);
60
61 GLfloat minOffset = 0.0f;
62 glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES, &minOffset);
63 EXPECT_LE(minOffset, -0.5f + std::pow(2, -bits));
64
65 GLfloat maxOffset = 0.0f;
66 glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES, &maxOffset);
67 EXPECT_GE(maxOffset, 0.5f - std::pow(2, -bits));
68
69 ASSERT_GL_NO_ERROR();
70 }
71 }
72
73 // Test gl_SampleMaskIn values with per-sample shading
TEST_P(SampleMultisampleInterpolationTest,SampleMaskInPerSample)74 TEST_P(SampleMultisampleInterpolationTest, SampleMaskInPerSample)
75 {
76 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_sample_variables"));
77 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
78
79 const char kVS[] = R"(#version 300 es
80 #extension GL_OES_shader_multisample_interpolation : require
81
82 in vec4 a_position;
83 sample out float interpolant;
84
85 void main()
86 {
87 gl_Position = a_position;
88 interpolant = 0.5;
89 })";
90
91 const char kFS[] = R"(#version 300 es
92 #extension GL_OES_sample_variables : require
93 #extension GL_OES_shader_multisample_interpolation : require
94
95 precision highp float;
96 sample in float interpolant;
97 out vec4 color;
98
99 bool isPow2(int v)
100 {
101 return v != 0 && (v & (v - 1)) == 0;
102 }
103
104 void main()
105 {
106 float r = float(isPow2(gl_SampleMaskIn[0]));
107 color = vec4(r, interpolant, 0, 1);
108 })";
109
110 ANGLE_GL_PROGRAM(program, kVS, kFS);
111 glUseProgram(program);
112
113 for (GLint sampleCount : {0, 4})
114 {
115 GLFramebuffer fbo;
116 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
117
118 GLRenderbuffer rbo;
119 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
120 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA8, 1, 1);
121 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
122 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
123
124 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
125 drawQuad(program, "a_position", 0.0);
126 ASSERT_GL_NO_ERROR();
127
128 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
129 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
130 glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
131
132 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
133 GLubyte pixel[4];
134 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
135 ASSERT_GL_NO_ERROR();
136
137 EXPECT_EQ(pixel[0], 255) << "Samples: " << sampleCount;
138 }
139 }
140
141 // Test gl_SampleMaskIn values with per-sample noperspective shading
TEST_P(SampleMultisampleInterpolationTest,SampleMaskInPerSampleNoPerspective)142 TEST_P(SampleMultisampleInterpolationTest, SampleMaskInPerSampleNoPerspective)
143 {
144 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_sample_variables"));
145 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
146 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_NV_shader_noperspective_interpolation"));
147
148 const char kVS[] = R"(#version 300 es
149 #extension GL_OES_shader_multisample_interpolation : require
150 #extension GL_NV_shader_noperspective_interpolation : require
151
152 in vec4 a_position;
153 noperspective sample out float interpolant;
154
155 void main()
156 {
157 gl_Position = a_position;
158 interpolant = 0.5;
159 })";
160
161 const char kFS[] = R"(#version 300 es
162 #extension GL_OES_sample_variables : require
163 #extension GL_OES_shader_multisample_interpolation : require
164 #extension GL_NV_shader_noperspective_interpolation : require
165
166 precision highp float;
167 noperspective sample in float interpolant;
168 out vec4 color;
169
170 bool isPow2(int v)
171 {
172 return v != 0 && (v & (v - 1)) == 0;
173 }
174
175 void main()
176 {
177 float r = float(isPow2(gl_SampleMaskIn[0]));
178 color = vec4(r, interpolant, 0, 1);
179 })";
180
181 ANGLE_GL_PROGRAM(program, kVS, kFS);
182 glUseProgram(program);
183
184 for (GLint sampleCount : {0, 4})
185 {
186 GLFramebuffer fbo;
187 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
188
189 GLRenderbuffer rbo;
190 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
191 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA8, 1, 1);
192 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
193 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
194
195 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
196 drawQuad(program, "a_position", 0.0);
197 ASSERT_GL_NO_ERROR();
198
199 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
200 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
201 glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
202
203 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
204 GLubyte pixel[4];
205 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
206 ASSERT_GL_NO_ERROR();
207
208 EXPECT_EQ(pixel[0], 255) << "Samples: " << sampleCount;
209 }
210 }
211
212 // Test that a shader with interpolateAt* calls and directly used interpolants compiles
213 // successfully.
TEST_P(SampleMultisampleInterpolationTest,CompileInterpolateAt)214 TEST_P(SampleMultisampleInterpolationTest, CompileInterpolateAt)
215 {
216 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation"));
217
218 EnsureGLExtensionEnabled("GL_NV_shader_noperspective_interpolation");
219
220 constexpr char kVS[] = R"(#version 300 es
221 #extension GL_OES_shader_multisample_interpolation : require
222 #extension GL_NV_shader_noperspective_interpolation : enable
223
224 precision highp float;
225
226 out float interpolant;
227 out float interpolantArray[2];
228
229 centroid out float interpolantCentroid;
230 centroid out float interpolantCentroidArray[2];
231
232 sample out float interpolantSample;
233 sample out float interpolantSampleArray[2];
234
235 smooth out float interpolantSmooth;
236 smooth out float interpolantSmoothArray[2];
237
238 flat out float interpolantFlat;
239 flat out float interpolantFlatArray[2];
240
241 #ifdef GL_NV_shader_noperspective_interpolation
242 noperspective out float interpolantNp;
243 noperspective out float interpolantNpArray[2];
244
245 noperspective centroid out float interpolantNpCentroid;
246 noperspective centroid out float interpolantNpCentroidArray[2];
247
248 noperspective sample out float interpolantNpSample;
249 noperspective sample out float interpolantNpSampleArray[2];
250 #endif
251
252 void main()
253 {
254 gl_Position = vec4(0, 0, 0, 1);
255
256 interpolant = 1.0;
257 interpolantArray[1] = 2.0;
258
259 interpolantCentroid = 3.0;
260 interpolantCentroidArray[1] = 4.0;
261
262 interpolantSample = 5.0;
263 interpolantSampleArray[1] = 6.0;
264
265 interpolantSmooth = 7.0;
266 interpolantSmoothArray[1] = 8.0;
267
268 interpolantFlat = 9.0;
269 interpolantFlatArray[1] = 10.0;
270
271 #ifdef GL_NV_shader_noperspective_interpolation
272 interpolantNp = 11.0;
273 interpolantNpArray[1] = 12.0;
274
275 interpolantNpCentroid = 13.0;
276 interpolantNpCentroidArray[1] = 14.0;
277
278 interpolantNpSample = 15.0;
279 interpolantNpSampleArray[1] = 16.0;
280 #endif
281 })";
282
283 constexpr char kFS[] = R"(#version 300 es
284 #extension GL_OES_shader_multisample_interpolation : require
285 #extension GL_NV_shader_noperspective_interpolation : enable
286
287 precision highp float;
288
289 in float interpolant;
290 in float interpolantArray[2];
291
292 centroid in float interpolantCentroid;
293 centroid in float interpolantCentroidArray[2];
294
295 sample in float interpolantSample;
296 sample in float interpolantSampleArray[2];
297
298 smooth in float interpolantSmooth;
299 smooth in float interpolantSmoothArray[2];
300
301 flat in float interpolantFlat;
302 flat in float interpolantFlatArray[2];
303
304 #ifdef GL_NV_shader_noperspective_interpolation
305 noperspective in float interpolantNp;
306 noperspective in float interpolantNpArray[2];
307
308 noperspective centroid in float interpolantNpCentroid;
309 noperspective centroid in float interpolantNpCentroidArray[2];
310
311 noperspective sample in float interpolantNpSample;
312 noperspective sample in float interpolantNpSampleArray[2];
313 #endif
314
315 out vec4 color;
316
317 void main()
318 {
319 float r;
320
321 r += interpolateAtCentroid(interpolant);
322 r += interpolateAtSample(interpolant, int(interpolant));
323 r += interpolateAtOffset(interpolant, vec2(interpolant));
324
325 r += interpolateAtCentroid(interpolantArray[1]);
326 r += interpolateAtSample(interpolantArray[1], int(interpolantArray[0]));
327 r += interpolateAtOffset(interpolantArray[1], vec2(interpolantArray[0]));
328
329 r += interpolateAtCentroid(interpolantCentroid);
330 r += interpolateAtSample(interpolantCentroid, int(interpolantCentroid));
331 r += interpolateAtOffset(interpolantCentroid, vec2(interpolantCentroid));
332
333 r += interpolateAtCentroid(interpolantCentroidArray[1]);
334 r += interpolateAtSample(interpolantCentroidArray[1], int(interpolantCentroidArray[0]));
335 r += interpolateAtOffset(interpolantCentroidArray[1], vec2(interpolantCentroidArray[0]));
336
337 r += interpolateAtCentroid(interpolantSample);
338 r += interpolateAtSample(interpolantSample, int(interpolantSample));
339 r += interpolateAtOffset(interpolantSample, vec2(interpolantSample));
340
341 r += interpolateAtCentroid(interpolantSampleArray[1]);
342 r += interpolateAtSample(interpolantSampleArray[1], int(interpolantSampleArray[0]));
343 r += interpolateAtOffset(interpolantSampleArray[1], vec2(interpolantSampleArray[0]));
344
345 r += interpolateAtCentroid(interpolantSmooth);
346 r += interpolateAtSample(interpolantSmooth, int(interpolantSmooth));
347 r += interpolateAtOffset(interpolantSmooth, vec2(interpolantSmooth));
348
349 r += interpolateAtCentroid(interpolantSmoothArray[1]);
350 r += interpolateAtSample(interpolantSmoothArray[1], int(interpolantSmoothArray[0]));
351 r += interpolateAtOffset(interpolantSmoothArray[1], vec2(interpolantSmoothArray[0]));
352
353 r += interpolateAtCentroid(interpolantFlat);
354 r += interpolateAtSample(interpolantFlat, int(interpolantFlat));
355 r += interpolateAtOffset(interpolantFlat, vec2(interpolantFlat));
356
357 r += interpolateAtCentroid(interpolantFlatArray[1]);
358 r += interpolateAtSample(interpolantFlatArray[1], int(interpolantFlatArray[0]));
359 r += interpolateAtOffset(interpolantFlatArray[1], vec2(interpolantFlatArray[0]));
360
361 #ifdef GL_NV_shader_noperspective_interpolation
362 r += interpolateAtCentroid(interpolantNp);
363 r += interpolateAtSample(interpolantNp, int(interpolantNp));
364 r += interpolateAtOffset(interpolantNp, vec2(interpolantNp));
365
366 r += interpolateAtCentroid(interpolantNpArray[1]);
367 r += interpolateAtSample(interpolantNpArray[1], int(interpolantNpArray[0]));
368 r += interpolateAtOffset(interpolantNpArray[1], vec2(interpolantNpArray[0]));
369
370 r += interpolateAtCentroid(interpolantNpCentroid);
371 r += interpolateAtSample(interpolantNpCentroid, int(interpolantNpCentroid));
372 r += interpolateAtOffset(interpolantNpCentroid, vec2(interpolantNpCentroid));
373
374 r += interpolateAtCentroid(interpolantNpCentroidArray[1]);
375 r += interpolateAtSample(interpolantNpCentroidArray[1], int(interpolantNpCentroidArray[0]));
376 r += interpolateAtOffset(interpolantNpCentroidArray[1], vec2(interpolantNpCentroidArray[0]));
377
378 r += interpolateAtCentroid(interpolantNpSample);
379 r += interpolateAtSample(interpolantNpSample, int(interpolantNpSample));
380 r += interpolateAtOffset(interpolantNpSample, vec2(interpolantNpSample));
381
382 r += interpolateAtCentroid(interpolantNpSampleArray[1]);
383 r += interpolateAtSample(interpolantNpSampleArray[1], int(interpolantNpSampleArray[0]));
384 r += interpolateAtOffset(interpolantNpSampleArray[1], vec2(interpolantNpSampleArray[0]));
385 #endif
386
387 color = vec4(r);
388 })";
389
390 ANGLE_GL_PROGRAM(program, kVS, kFS);
391 }
392
393 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SampleMultisampleInterpolationTest);
394 ANGLE_INSTANTIATE_TEST_ES3(SampleMultisampleInterpolationTest);
395
396 } // anonymous namespace
397