blob: 6b7f26555b7c89990ed67874492c64de44bd6236 [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
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.
Cooper Partine6664f02015-01-09 16:22:24 -08005//
6// Some of the pointsprite tests below were ported from Khronos WebGL
7// conformance test suite.
8
Corentin Wallezd3970de2015-05-14 11:07:48 -04009#include "test_utils/ANGLETest.h"
Cooper Partine6664f02015-01-09 16:22:24 -080010
Corentin Wallezf0c1d022015-06-18 18:37:09 -070011#include <cmath>
12
Jamie Madillfa05f602015-05-07 13:47:11 -040013using namespace angle;
14
Cooper Partine6664f02015-01-09 16:22:24 -080015class PointSpritesTest : public ANGLETest
16{
17 protected:
18 const int windowWidth = 256;
19 const int windowHeight = 256;
Jamie Madillfa05f602015-05-07 13:47:11 -040020 PointSpritesTest()
Cooper Partine6664f02015-01-09 16:22:24 -080021 {
22 setWindowWidth(windowWidth);
23 setWindowHeight(windowHeight);
24 setConfigRedBits(8);
25 setConfigGreenBits(8);
26 setConfigBlueBits(8);
27 setConfigAlphaBits(8);
28 }
29
30 virtual void SetUp()
31 {
32 ANGLETest::SetUp();
33 }
34
35 float s2p(float s)
36 {
37 return (s + 1.0f) * 0.5f * (GLfloat)windowWidth;
38 }
39};
40
41// Checks gl_PointCoord and gl_PointSize
42// https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/variables/gl-pointcoord.html
Jamie Madillfa05f602015-05-07 13:47:11 -040043TEST_P(PointSpritesTest, PointCoordAndPointSizeCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -080044{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -040045 // TODO(jmadill): figure out why this fails
46 if (isIntel() && GetParam() == ES2_D3D9())
47 {
48 std::cout << "Test skipped on Intel due to failures." << std::endl;
49 return;
50 }
51
Cooper Partine6664f02015-01-09 16:22:24 -080052 const std::string fs = SHADER_SOURCE
53 (
54 precision mediump float;
55 void main()
56 {
57 gl_FragColor = vec4(
58 gl_PointCoord.x,
59 gl_PointCoord.y,
60 0,
61 1);
62 }
63 );
64
65 const std::string vs = SHADER_SOURCE
66 (
67 attribute vec4 vPosition;
68 uniform float uPointSize;
69 void main()
70 {
71 gl_PointSize = uPointSize;
72 gl_Position = vPosition;
73 }
74 );
75
76 GLuint program = CompileProgram(vs, fs);
77 ASSERT_NE(program, 0u);
78 ASSERT_GL_NO_ERROR();
79
80 glUseProgram(program);
81
82 GLfloat pointSizeRange[2] = {};
83 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
84
85 GLfloat maxPointSize = pointSizeRange[1];
86
87 ASSERT_TRUE(maxPointSize >= 1);
88 maxPointSize = floorf(maxPointSize);
89 ASSERT_TRUE((int)maxPointSize % 1 == 0);
90
91 maxPointSize = std::min(maxPointSize, 64.0f);
92 GLfloat pointWidth = maxPointSize / windowWidth;
Minmin Gong794e0002015-04-07 18:31:54 -070093 GLint step = static_cast<GLint>(floorf(maxPointSize / 4));
94 GLint pointStep = std::max<GLint>(1, step);
Cooper Partine6664f02015-01-09 16:22:24 -080095
96 GLint pointSizeLoc = glGetUniformLocation(program, "uPointSize");
97 ASSERT_GL_NO_ERROR();
98
99 glUniform1f(pointSizeLoc, maxPointSize);
100 ASSERT_GL_NO_ERROR();
101
102 GLfloat pixelOffset = ((int)maxPointSize % 2) ? (1.0f / (GLfloat)windowWidth) : 0;
103 GLuint vertexObject = 0;
104 glGenBuffers(1, &vertexObject);
105 ASSERT_NE(vertexObject, 0U);
106 ASSERT_GL_NO_ERROR();
107
108 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
109 ASSERT_GL_NO_ERROR();
110
Minmin Gong794e0002015-04-07 18:31:54 -0700111 GLfloat thePoints[] = { -0.5f + pixelOffset, -0.5f + pixelOffset,
112 0.5f + pixelOffset, -0.5f + pixelOffset,
113 -0.5f + pixelOffset, 0.5f + pixelOffset,
114 0.5f + pixelOffset, 0.5f + pixelOffset };
Cooper Partine6664f02015-01-09 16:22:24 -0800115
116 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
117 ASSERT_GL_NO_ERROR();
118
119 glEnableVertexAttribArray(0);
120 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
121
122 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
123
124 glDrawArrays(GL_POINTS, 0, 4);
125 ASSERT_GL_NO_ERROR();
126
127 glDeleteBuffers(1, &vertexObject);
128
129 std::string debugText;
130 for (float py = 0; py < 2; ++py) {
131 for (float px = 0; px < 2; ++px) {
Minmin Gong794e0002015-04-07 18:31:54 -0700132 float pointX = -0.5f + px + pixelOffset;
133 float pointY = -0.5f + py + pixelOffset;
Cooper Partine6664f02015-01-09 16:22:24 -0800134 for (int yy = 0; yy < maxPointSize; yy += pointStep) {
135 for (int xx = 0; xx < maxPointSize; xx += pointStep) {
136 // formula for s and t from OpenGL ES 2.0 spec section 3.3
137 float xw = s2p(pointX);
138 float yw = s2p(pointY);
139 float u = xx / maxPointSize * 2 - 1;
140 float v = yy / maxPointSize * 2 - 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700141 int xf = static_cast<int>(floorf(s2p(pointX + u * pointWidth)));
142 int yf = static_cast<int>(floorf(s2p(pointY + v * pointWidth)));
143 float s = 0.5f + (xf + 0.5f - xw) / maxPointSize;
144 float t = 0.5f + (yf + 0.5f - yw) / maxPointSize;
145 GLubyte color[4] = { static_cast<GLubyte>(floorf(s * 255)), static_cast<GLubyte>(floorf((1 - t) * 255)), 0, 255 };
Cooper Partine6664f02015-01-09 16:22:24 -0800146 EXPECT_PIXEL_NEAR(xf, yf, color[0], color[1], color[2], color[3], 4);
147 }
148 }
149 }
150 }
151}
152
153// Verify that drawing a point without enabling any attributes succeeds
154// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-no-attributes.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400155TEST_P(PointSpritesTest, PointWithoutAttributesCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800156{
Geoff Lange0cc2a42016-01-20 10:58:17 -0500157 // clang-format off
Cooper Partine6664f02015-01-09 16:22:24 -0800158 const std::string fs = SHADER_SOURCE
159 (
160 precision mediump float;
161 void main()
162 {
163 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
164 }
165 );
166
167 const std::string vs = SHADER_SOURCE
168 (
169 void main()
170 {
Geoff Lange0cc2a42016-01-20 10:58:17 -0500171 gl_PointSize = 2.0;
Cooper Partine6664f02015-01-09 16:22:24 -0800172 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
173 }
174 );
Geoff Lange0cc2a42016-01-20 10:58:17 -0500175 // clang-format on
Cooper Partine6664f02015-01-09 16:22:24 -0800176
177 GLuint program = CompileProgram(vs, fs);
178 ASSERT_NE(program, 0u);
179 ASSERT_GL_NO_ERROR();
180
181 glUseProgram(program);
182
183 glDrawArrays(GL_POINTS, 0, 1);
184 ASSERT_GL_NO_ERROR();
185
186 // expect the center pixel to be green
187 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
188}
189
190// This is a regression test for a graphics driver bug affecting end caps on roads in MapsGL
191// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-with-gl-pointcoord-in-fragment-shader.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400192TEST_P(PointSpritesTest, PointCoordRegressionTest)
Cooper Partine6664f02015-01-09 16:22:24 -0800193{
194 const std::string fs = SHADER_SOURCE
195 (
196 precision mediump float;
197 varying vec4 v_color;
198 void main()
199 {
200 // It seems as long as this mathematical expression references
201 // gl_PointCoord, the fragment's color is incorrect.
202 vec2 diff = gl_PointCoord - vec2(.5, .5);
203 if (length(diff) > 0.5)
204 discard;
205
206 // The point should be a solid color.
207 gl_FragColor = v_color;
208 }
209 );
210
211 const std::string vs = SHADER_SOURCE
212 (
213 varying vec4 v_color;
214 // The X and Y coordinates of the center of the point.
215 attribute vec2 a_vertex;
216 uniform float u_pointSize;
217 void main()
218 {
219 gl_PointSize = u_pointSize;
220 gl_Position = vec4(a_vertex, 0.0, 1.0);
221 // The color of the point.
222 v_color = vec4(0.0, 1.0, 0.0, 1.0);
223 }
224 );
225
226 GLuint program = CompileProgram(vs, fs);
227 ASSERT_NE(program, 0u);
228 ASSERT_GL_NO_ERROR();
229
230 glUseProgram(program);
231
232 GLfloat pointSizeRange[2] = {};
233 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
234
235 GLfloat maxPointSize = pointSizeRange[1];
236
237 ASSERT_TRUE(maxPointSize > 2);
238
239 glClearColor(0, 0, 0, 1);
240 glDisable(GL_DEPTH_TEST);
241 glClear(GL_COLOR_BUFFER_BIT);
242
243 GLint pointSizeLoc = glGetUniformLocation(program, "u_pointSize");
244 ASSERT_GL_NO_ERROR();
245
246 GLfloat pointSize = std::min<GLfloat>(20.0f, maxPointSize);
247 glUniform1f(pointSizeLoc, pointSize);
248 ASSERT_GL_NO_ERROR();
249
250 GLuint vertexObject = 0;
251 glGenBuffers(1, &vertexObject);
252 ASSERT_NE(vertexObject, 0U);
253 ASSERT_GL_NO_ERROR();
254
255 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
256 ASSERT_GL_NO_ERROR();
257
258 GLfloat thePoints[] = { 0.0f, 0.0f };
259
260 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
261 ASSERT_GL_NO_ERROR();
262
263 glEnableVertexAttribArray(0);
264 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
265
266 glDrawArrays(GL_POINTS, 0, 1);
267 ASSERT_GL_NO_ERROR();
268
269 // expect the center pixel to be green
270 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
271
272 glDeleteBuffers(1, &vertexObject);
273}
274
275// Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled
276// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-size.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400277TEST_P(PointSpritesTest, PointSizeEnabledCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800278{
279 const std::string fs = SHADER_SOURCE
280 (
281 precision mediump float;
282 varying vec4 color;
283
284 void main()
285 {
286 gl_FragColor = color;
287 }
288 );
289
290 const std::string vs = SHADER_SOURCE
291 (
292 attribute vec3 pos;
293 attribute vec4 colorIn;
294 uniform float pointSize;
295 varying vec4 color;
296
297 void main()
298 {
299 gl_PointSize = pointSize;
300 color = colorIn;
301 gl_Position = vec4(pos, 1.0);
302 }
303 );
304
Austin Kinrossfbd78202015-05-28 15:33:55 -0700305 // The WebGL test is drawn on a 2x2 canvas. Emulate this by setting a 2x2 viewport.
306 glViewport(0, 0, 2, 2);
307
Cooper Partine6664f02015-01-09 16:22:24 -0800308 GLuint program = CompileProgram(vs, fs);
309 ASSERT_NE(program, 0u);
310 ASSERT_GL_NO_ERROR();
311
312 glUseProgram(program);
313
314 glDisable(GL_BLEND);
315
316 // The choice of (0.4, 0.4) ensures that the centers of the surrounding
317 // pixels are not contained within the point when it is of size 1, but
318 // that they definitely are when it is of size 2.
319 GLfloat vertices[] = { 0.4f, 0.4f, 0.0f };
320 GLubyte colors[] = { 255, 0, 0, 255 };
321
322 GLuint vertexObject = 0;
323 glGenBuffers(1, &vertexObject);
324 ASSERT_NE(vertexObject, 0U);
325 ASSERT_GL_NO_ERROR();
326
327 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
328 ASSERT_GL_NO_ERROR();
329
330 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
331 ASSERT_GL_NO_ERROR();
332
333 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
334 ASSERT_GL_NO_ERROR();
335
336 glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
337 ASSERT_GL_NO_ERROR();
338
339 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
340
341 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
342 glEnableVertexAttribArray(0);
343
344 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (GLvoid*)sizeof(vertices));
345 glEnableVertexAttribArray(1);
346
347 GLint pointSizeLoc = glGetUniformLocation(program, "pointSize");
348 ASSERT_GL_NO_ERROR();
349
350 glUniform1f(pointSizeLoc, 1.0f);
351 ASSERT_GL_NO_ERROR();
352
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700353 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800354 ASSERT_GL_NO_ERROR();
355
356 // Test the pixels around the target Red pixel to ensure
357 // they are the expected color values
Austin Kinrossfbd78202015-05-28 15:33:55 -0700358 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800359 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700360 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800361 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700362 // 1x1 is expected to be a red pixel
Cooper Partine6664f02015-01-09 16:22:24 -0800363 // All others are black
364 GLubyte expectedColor[4] = { 0, 0, 0, 0 };
Austin Kinrossfbd78202015-05-28 15:33:55 -0700365 if (x == 1 && y == 1)
Cooper Partine6664f02015-01-09 16:22:24 -0800366 {
367 expectedColor[0] = 255;
368 expectedColor[3] = 255;
369 }
370 EXPECT_PIXEL_EQ(x, y, expectedColor[0], expectedColor[1], expectedColor[2], expectedColor[3]);
371 }
372 }
373
Cooper Partine6664f02015-01-09 16:22:24 -0800374 GLfloat pointSizeRange[2] = {};
375 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
376
377 if (pointSizeRange[1] >= 2.0)
378 {
379 // Draw a point of size 2 and verify it fills the appropriate region.
380 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
381
382 glUniform1f(pointSizeLoc, 2.0f);
383 ASSERT_GL_NO_ERROR();
384
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700385 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800386 ASSERT_GL_NO_ERROR();
387
388 // Test the pixels to ensure the target is ALL Red pixels
Austin Kinrossfbd78202015-05-28 15:33:55 -0700389 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800390 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700391 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800392 {
393 EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
394 }
395 }
396 }
397
398 glDeleteBuffers(1, &vertexObject);
399}
Cooper Partin4e47b922015-02-03 09:04:20 -0800400
401// Verify that rendering works correctly when gl_PointSize is declared in a shader but isn't used
Jamie Madillfa05f602015-05-07 13:47:11 -0400402TEST_P(PointSpritesTest, PointSizeDeclaredButUnused)
Cooper Partin4e47b922015-02-03 09:04:20 -0800403{
404 const std::string vs = SHADER_SOURCE
405 (
406 attribute highp vec4 position;
407
408 void main(void)
409 {
410 gl_PointSize = 1.0;
411 gl_Position = position;
412 }
413 );
414
415 const std::string fs = SHADER_SOURCE
416 (
417 void main(void)
418 {
419 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
420 }
421 );
422
423 GLuint program = CompileProgram(vs, fs);
424 ASSERT_NE(program, 0u);
425 ASSERT_GL_NO_ERROR();
426
427 glUseProgram(program);
428 drawQuad(program, "position", 0.5f, 1.0f);
429 ASSERT_GL_NO_ERROR();
430
431 // expect the center pixel to be red
432 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
433
434 glDeleteProgram(program);
435}
Jamie Madillfa05f602015-05-07 13:47:11 -0400436
437// Use this to select which configurations (e.g. which renderer, which GLES
438// major version) these tests should be run against.
439//
440// We test on D3D11 9_3 because the existing D3D11 PointSprite implementation
441// uses Geometry Shaders which are not supported for 9_3.
442// D3D9 and D3D11 are also tested to ensure no regressions.
Geoff Lange0cc2a42016-01-20 10:58:17 -0500443ANGLE_INSTANTIATE_TEST(PointSpritesTest,
444 ES2_D3D9(),
445 ES2_D3D11(),
446 ES2_D3D11_FL9_3(),
447 ES2_OPENGL(),
448 ES2_OPENGLES());