blob: 2ad2e01b3659f953998dadf5e6e36e87e114422d [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{
157 const std::string fs = SHADER_SOURCE
158 (
159 precision mediump float;
160 void main()
161 {
162 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
163 }
164 );
165
166 const std::string vs = SHADER_SOURCE
167 (
168 void main()
169 {
170 gl_PointSize = 1.0;
171 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
172 }
173 );
174
175 GLuint program = CompileProgram(vs, fs);
176 ASSERT_NE(program, 0u);
177 ASSERT_GL_NO_ERROR();
178
179 glUseProgram(program);
180
181 glDrawArrays(GL_POINTS, 0, 1);
182 ASSERT_GL_NO_ERROR();
183
184 // expect the center pixel to be green
185 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
186}
187
188// This is a regression test for a graphics driver bug affecting end caps on roads in MapsGL
189// 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 -0400190TEST_P(PointSpritesTest, PointCoordRegressionTest)
Cooper Partine6664f02015-01-09 16:22:24 -0800191{
192 const std::string fs = SHADER_SOURCE
193 (
194 precision mediump float;
195 varying vec4 v_color;
196 void main()
197 {
198 // It seems as long as this mathematical expression references
199 // gl_PointCoord, the fragment's color is incorrect.
200 vec2 diff = gl_PointCoord - vec2(.5, .5);
201 if (length(diff) > 0.5)
202 discard;
203
204 // The point should be a solid color.
205 gl_FragColor = v_color;
206 }
207 );
208
209 const std::string vs = SHADER_SOURCE
210 (
211 varying vec4 v_color;
212 // The X and Y coordinates of the center of the point.
213 attribute vec2 a_vertex;
214 uniform float u_pointSize;
215 void main()
216 {
217 gl_PointSize = u_pointSize;
218 gl_Position = vec4(a_vertex, 0.0, 1.0);
219 // The color of the point.
220 v_color = vec4(0.0, 1.0, 0.0, 1.0);
221 }
222 );
223
224 GLuint program = CompileProgram(vs, fs);
225 ASSERT_NE(program, 0u);
226 ASSERT_GL_NO_ERROR();
227
228 glUseProgram(program);
229
230 GLfloat pointSizeRange[2] = {};
231 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
232
233 GLfloat maxPointSize = pointSizeRange[1];
234
235 ASSERT_TRUE(maxPointSize > 2);
236
237 glClearColor(0, 0, 0, 1);
238 glDisable(GL_DEPTH_TEST);
239 glClear(GL_COLOR_BUFFER_BIT);
240
241 GLint pointSizeLoc = glGetUniformLocation(program, "u_pointSize");
242 ASSERT_GL_NO_ERROR();
243
244 GLfloat pointSize = std::min<GLfloat>(20.0f, maxPointSize);
245 glUniform1f(pointSizeLoc, pointSize);
246 ASSERT_GL_NO_ERROR();
247
248 GLuint vertexObject = 0;
249 glGenBuffers(1, &vertexObject);
250 ASSERT_NE(vertexObject, 0U);
251 ASSERT_GL_NO_ERROR();
252
253 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
254 ASSERT_GL_NO_ERROR();
255
256 GLfloat thePoints[] = { 0.0f, 0.0f };
257
258 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
259 ASSERT_GL_NO_ERROR();
260
261 glEnableVertexAttribArray(0);
262 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
263
264 glDrawArrays(GL_POINTS, 0, 1);
265 ASSERT_GL_NO_ERROR();
266
267 // expect the center pixel to be green
268 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
269
270 glDeleteBuffers(1, &vertexObject);
271}
272
273// Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled
274// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-size.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400275TEST_P(PointSpritesTest, PointSizeEnabledCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800276{
277 const std::string fs = SHADER_SOURCE
278 (
279 precision mediump float;
280 varying vec4 color;
281
282 void main()
283 {
284 gl_FragColor = color;
285 }
286 );
287
288 const std::string vs = SHADER_SOURCE
289 (
290 attribute vec3 pos;
291 attribute vec4 colorIn;
292 uniform float pointSize;
293 varying vec4 color;
294
295 void main()
296 {
297 gl_PointSize = pointSize;
298 color = colorIn;
299 gl_Position = vec4(pos, 1.0);
300 }
301 );
302
Austin Kinrossfbd78202015-05-28 15:33:55 -0700303 // The WebGL test is drawn on a 2x2 canvas. Emulate this by setting a 2x2 viewport.
304 glViewport(0, 0, 2, 2);
305
Cooper Partine6664f02015-01-09 16:22:24 -0800306 GLuint program = CompileProgram(vs, fs);
307 ASSERT_NE(program, 0u);
308 ASSERT_GL_NO_ERROR();
309
310 glUseProgram(program);
311
312 glDisable(GL_BLEND);
313
314 // The choice of (0.4, 0.4) ensures that the centers of the surrounding
315 // pixels are not contained within the point when it is of size 1, but
316 // that they definitely are when it is of size 2.
317 GLfloat vertices[] = { 0.4f, 0.4f, 0.0f };
318 GLubyte colors[] = { 255, 0, 0, 255 };
319
320 GLuint vertexObject = 0;
321 glGenBuffers(1, &vertexObject);
322 ASSERT_NE(vertexObject, 0U);
323 ASSERT_GL_NO_ERROR();
324
325 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
326 ASSERT_GL_NO_ERROR();
327
328 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
329 ASSERT_GL_NO_ERROR();
330
331 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
332 ASSERT_GL_NO_ERROR();
333
334 glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
335 ASSERT_GL_NO_ERROR();
336
337 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
338
339 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
340 glEnableVertexAttribArray(0);
341
342 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (GLvoid*)sizeof(vertices));
343 glEnableVertexAttribArray(1);
344
345 GLint pointSizeLoc = glGetUniformLocation(program, "pointSize");
346 ASSERT_GL_NO_ERROR();
347
348 glUniform1f(pointSizeLoc, 1.0f);
349 ASSERT_GL_NO_ERROR();
350
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700351 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800352 ASSERT_GL_NO_ERROR();
353
354 // Test the pixels around the target Red pixel to ensure
355 // they are the expected color values
Austin Kinrossfbd78202015-05-28 15:33:55 -0700356 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800357 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700358 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800359 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700360 // 1x1 is expected to be a red pixel
Cooper Partine6664f02015-01-09 16:22:24 -0800361 // All others are black
362 GLubyte expectedColor[4] = { 0, 0, 0, 0 };
Austin Kinrossfbd78202015-05-28 15:33:55 -0700363 if (x == 1 && y == 1)
Cooper Partine6664f02015-01-09 16:22:24 -0800364 {
365 expectedColor[0] = 255;
366 expectedColor[3] = 255;
367 }
368 EXPECT_PIXEL_EQ(x, y, expectedColor[0], expectedColor[1], expectedColor[2], expectedColor[3]);
369 }
370 }
371
Cooper Partine6664f02015-01-09 16:22:24 -0800372 GLfloat pointSizeRange[2] = {};
373 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
374
375 if (pointSizeRange[1] >= 2.0)
376 {
377 // Draw a point of size 2 and verify it fills the appropriate region.
378 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
379
380 glUniform1f(pointSizeLoc, 2.0f);
381 ASSERT_GL_NO_ERROR();
382
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700383 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800384 ASSERT_GL_NO_ERROR();
385
386 // Test the pixels to ensure the target is ALL Red pixels
Austin Kinrossfbd78202015-05-28 15:33:55 -0700387 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800388 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700389 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800390 {
391 EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
392 }
393 }
394 }
395
396 glDeleteBuffers(1, &vertexObject);
397}
Cooper Partin4e47b922015-02-03 09:04:20 -0800398
399// Verify that rendering works correctly when gl_PointSize is declared in a shader but isn't used
Jamie Madillfa05f602015-05-07 13:47:11 -0400400TEST_P(PointSpritesTest, PointSizeDeclaredButUnused)
Cooper Partin4e47b922015-02-03 09:04:20 -0800401{
402 const std::string vs = SHADER_SOURCE
403 (
404 attribute highp vec4 position;
405
406 void main(void)
407 {
408 gl_PointSize = 1.0;
409 gl_Position = position;
410 }
411 );
412
413 const std::string fs = SHADER_SOURCE
414 (
415 void main(void)
416 {
417 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
418 }
419 );
420
421 GLuint program = CompileProgram(vs, fs);
422 ASSERT_NE(program, 0u);
423 ASSERT_GL_NO_ERROR();
424
425 glUseProgram(program);
426 drawQuad(program, "position", 0.5f, 1.0f);
427 ASSERT_GL_NO_ERROR();
428
429 // expect the center pixel to be red
430 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
431
432 glDeleteProgram(program);
433}
Jamie Madillfa05f602015-05-07 13:47:11 -0400434
435// Use this to select which configurations (e.g. which renderer, which GLES
436// major version) these tests should be run against.
437//
438// We test on D3D11 9_3 because the existing D3D11 PointSprite implementation
439// uses Geometry Shaders which are not supported for 9_3.
440// D3D9 and D3D11 are also tested to ensure no regressions.
Geoff Lang3cca86b2015-07-23 19:30:46 +0000441ANGLE_INSTANTIATE_TEST(PointSpritesTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());