blob: 05302517c471de9f8e325d3bfe204d7da7db6a5d [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
Jamie Madillfa05f602015-05-07 13:47:11 -040011using namespace angle;
12
Cooper Partine6664f02015-01-09 16:22:24 -080013class PointSpritesTest : public ANGLETest
14{
15 protected:
16 const int windowWidth = 256;
17 const int windowHeight = 256;
Jamie Madillfa05f602015-05-07 13:47:11 -040018 PointSpritesTest()
Cooper Partine6664f02015-01-09 16:22:24 -080019 {
20 setWindowWidth(windowWidth);
21 setWindowHeight(windowHeight);
22 setConfigRedBits(8);
23 setConfigGreenBits(8);
24 setConfigBlueBits(8);
25 setConfigAlphaBits(8);
26 }
27
28 virtual void SetUp()
29 {
30 ANGLETest::SetUp();
31 }
32
33 float s2p(float s)
34 {
35 return (s + 1.0f) * 0.5f * (GLfloat)windowWidth;
36 }
37};
38
39// Checks gl_PointCoord and gl_PointSize
40// https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/variables/gl-pointcoord.html
Jamie Madillfa05f602015-05-07 13:47:11 -040041TEST_P(PointSpritesTest, PointCoordAndPointSizeCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -080042{
43 const std::string fs = SHADER_SOURCE
44 (
45 precision mediump float;
46 void main()
47 {
48 gl_FragColor = vec4(
49 gl_PointCoord.x,
50 gl_PointCoord.y,
51 0,
52 1);
53 }
54 );
55
56 const std::string vs = SHADER_SOURCE
57 (
58 attribute vec4 vPosition;
59 uniform float uPointSize;
60 void main()
61 {
62 gl_PointSize = uPointSize;
63 gl_Position = vPosition;
64 }
65 );
66
67 GLuint program = CompileProgram(vs, fs);
68 ASSERT_NE(program, 0u);
69 ASSERT_GL_NO_ERROR();
70
71 glUseProgram(program);
72
73 GLfloat pointSizeRange[2] = {};
74 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
75
76 GLfloat maxPointSize = pointSizeRange[1];
77
78 ASSERT_TRUE(maxPointSize >= 1);
79 maxPointSize = floorf(maxPointSize);
80 ASSERT_TRUE((int)maxPointSize % 1 == 0);
81
82 maxPointSize = std::min(maxPointSize, 64.0f);
83 GLfloat pointWidth = maxPointSize / windowWidth;
Minmin Gong794e0002015-04-07 18:31:54 -070084 GLint step = static_cast<GLint>(floorf(maxPointSize / 4));
85 GLint pointStep = std::max<GLint>(1, step);
Cooper Partine6664f02015-01-09 16:22:24 -080086
87 GLint pointSizeLoc = glGetUniformLocation(program, "uPointSize");
88 ASSERT_GL_NO_ERROR();
89
90 glUniform1f(pointSizeLoc, maxPointSize);
91 ASSERT_GL_NO_ERROR();
92
93 GLfloat pixelOffset = ((int)maxPointSize % 2) ? (1.0f / (GLfloat)windowWidth) : 0;
94 GLuint vertexObject = 0;
95 glGenBuffers(1, &vertexObject);
96 ASSERT_NE(vertexObject, 0U);
97 ASSERT_GL_NO_ERROR();
98
99 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
100 ASSERT_GL_NO_ERROR();
101
Minmin Gong794e0002015-04-07 18:31:54 -0700102 GLfloat thePoints[] = { -0.5f + pixelOffset, -0.5f + pixelOffset,
103 0.5f + pixelOffset, -0.5f + pixelOffset,
104 -0.5f + pixelOffset, 0.5f + pixelOffset,
105 0.5f + pixelOffset, 0.5f + pixelOffset };
Cooper Partine6664f02015-01-09 16:22:24 -0800106
107 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
108 ASSERT_GL_NO_ERROR();
109
110 glEnableVertexAttribArray(0);
111 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
112
113 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
114
115 glDrawArrays(GL_POINTS, 0, 4);
116 ASSERT_GL_NO_ERROR();
117
118 glDeleteBuffers(1, &vertexObject);
119
120 std::string debugText;
121 for (float py = 0; py < 2; ++py) {
122 for (float px = 0; px < 2; ++px) {
Minmin Gong794e0002015-04-07 18:31:54 -0700123 float pointX = -0.5f + px + pixelOffset;
124 float pointY = -0.5f + py + pixelOffset;
Cooper Partine6664f02015-01-09 16:22:24 -0800125 for (int yy = 0; yy < maxPointSize; yy += pointStep) {
126 for (int xx = 0; xx < maxPointSize; xx += pointStep) {
127 // formula for s and t from OpenGL ES 2.0 spec section 3.3
128 float xw = s2p(pointX);
129 float yw = s2p(pointY);
130 float u = xx / maxPointSize * 2 - 1;
131 float v = yy / maxPointSize * 2 - 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700132 int xf = static_cast<int>(floorf(s2p(pointX + u * pointWidth)));
133 int yf = static_cast<int>(floorf(s2p(pointY + v * pointWidth)));
134 float s = 0.5f + (xf + 0.5f - xw) / maxPointSize;
135 float t = 0.5f + (yf + 0.5f - yw) / maxPointSize;
136 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 -0800137 EXPECT_PIXEL_NEAR(xf, yf, color[0], color[1], color[2], color[3], 4);
138 }
139 }
140 }
141 }
142}
143
144// Verify that drawing a point without enabling any attributes succeeds
145// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-no-attributes.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400146TEST_P(PointSpritesTest, PointWithoutAttributesCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800147{
148 const std::string fs = SHADER_SOURCE
149 (
150 precision mediump float;
151 void main()
152 {
153 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
154 }
155 );
156
157 const std::string vs = SHADER_SOURCE
158 (
159 void main()
160 {
161 gl_PointSize = 1.0;
162 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
163 }
164 );
165
166 GLuint program = CompileProgram(vs, fs);
167 ASSERT_NE(program, 0u);
168 ASSERT_GL_NO_ERROR();
169
170 glUseProgram(program);
171
172 glDrawArrays(GL_POINTS, 0, 1);
173 ASSERT_GL_NO_ERROR();
174
175 // expect the center pixel to be green
176 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
177}
178
179// This is a regression test for a graphics driver bug affecting end caps on roads in MapsGL
180// 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 -0400181TEST_P(PointSpritesTest, PointCoordRegressionTest)
Cooper Partine6664f02015-01-09 16:22:24 -0800182{
183 const std::string fs = SHADER_SOURCE
184 (
185 precision mediump float;
186 varying vec4 v_color;
187 void main()
188 {
189 // It seems as long as this mathematical expression references
190 // gl_PointCoord, the fragment's color is incorrect.
191 vec2 diff = gl_PointCoord - vec2(.5, .5);
192 if (length(diff) > 0.5)
193 discard;
194
195 // The point should be a solid color.
196 gl_FragColor = v_color;
197 }
198 );
199
200 const std::string vs = SHADER_SOURCE
201 (
202 varying vec4 v_color;
203 // The X and Y coordinates of the center of the point.
204 attribute vec2 a_vertex;
205 uniform float u_pointSize;
206 void main()
207 {
208 gl_PointSize = u_pointSize;
209 gl_Position = vec4(a_vertex, 0.0, 1.0);
210 // The color of the point.
211 v_color = vec4(0.0, 1.0, 0.0, 1.0);
212 }
213 );
214
215 GLuint program = CompileProgram(vs, fs);
216 ASSERT_NE(program, 0u);
217 ASSERT_GL_NO_ERROR();
218
219 glUseProgram(program);
220
221 GLfloat pointSizeRange[2] = {};
222 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
223
224 GLfloat maxPointSize = pointSizeRange[1];
225
226 ASSERT_TRUE(maxPointSize > 2);
227
228 glClearColor(0, 0, 0, 1);
229 glDisable(GL_DEPTH_TEST);
230 glClear(GL_COLOR_BUFFER_BIT);
231
232 GLint pointSizeLoc = glGetUniformLocation(program, "u_pointSize");
233 ASSERT_GL_NO_ERROR();
234
235 GLfloat pointSize = std::min<GLfloat>(20.0f, maxPointSize);
236 glUniform1f(pointSizeLoc, pointSize);
237 ASSERT_GL_NO_ERROR();
238
239 GLuint vertexObject = 0;
240 glGenBuffers(1, &vertexObject);
241 ASSERT_NE(vertexObject, 0U);
242 ASSERT_GL_NO_ERROR();
243
244 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
245 ASSERT_GL_NO_ERROR();
246
247 GLfloat thePoints[] = { 0.0f, 0.0f };
248
249 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
250 ASSERT_GL_NO_ERROR();
251
252 glEnableVertexAttribArray(0);
253 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
254
255 glDrawArrays(GL_POINTS, 0, 1);
256 ASSERT_GL_NO_ERROR();
257
258 // expect the center pixel to be green
259 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
260
261 glDeleteBuffers(1, &vertexObject);
262}
263
264// Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled
265// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-size.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400266TEST_P(PointSpritesTest, PointSizeEnabledCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800267{
268 const std::string fs = SHADER_SOURCE
269 (
270 precision mediump float;
271 varying vec4 color;
272
273 void main()
274 {
275 gl_FragColor = color;
276 }
277 );
278
279 const std::string vs = SHADER_SOURCE
280 (
281 attribute vec3 pos;
282 attribute vec4 colorIn;
283 uniform float pointSize;
284 varying vec4 color;
285
286 void main()
287 {
288 gl_PointSize = pointSize;
289 color = colorIn;
290 gl_Position = vec4(pos, 1.0);
291 }
292 );
293
Austin Kinrossfbd78202015-05-28 15:33:55 -0700294 // The WebGL test is drawn on a 2x2 canvas. Emulate this by setting a 2x2 viewport.
295 glViewport(0, 0, 2, 2);
296
Cooper Partine6664f02015-01-09 16:22:24 -0800297 GLuint program = CompileProgram(vs, fs);
298 ASSERT_NE(program, 0u);
299 ASSERT_GL_NO_ERROR();
300
301 glUseProgram(program);
302
303 glDisable(GL_BLEND);
304
305 // The choice of (0.4, 0.4) ensures that the centers of the surrounding
306 // pixels are not contained within the point when it is of size 1, but
307 // that they definitely are when it is of size 2.
308 GLfloat vertices[] = { 0.4f, 0.4f, 0.0f };
309 GLubyte colors[] = { 255, 0, 0, 255 };
310
311 GLuint vertexObject = 0;
312 glGenBuffers(1, &vertexObject);
313 ASSERT_NE(vertexObject, 0U);
314 ASSERT_GL_NO_ERROR();
315
316 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
317 ASSERT_GL_NO_ERROR();
318
319 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
320 ASSERT_GL_NO_ERROR();
321
322 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
323 ASSERT_GL_NO_ERROR();
324
325 glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
326 ASSERT_GL_NO_ERROR();
327
328 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
329
330 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
331 glEnableVertexAttribArray(0);
332
333 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (GLvoid*)sizeof(vertices));
334 glEnableVertexAttribArray(1);
335
336 GLint pointSizeLoc = glGetUniformLocation(program, "pointSize");
337 ASSERT_GL_NO_ERROR();
338
339 glUniform1f(pointSizeLoc, 1.0f);
340 ASSERT_GL_NO_ERROR();
341
Corentin Wallez973402f2015-05-11 13:42:22 -0400342 glDrawArrays(GL_POINTS, 0, ArraySize(vertices) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800343 ASSERT_GL_NO_ERROR();
344
345 // Test the pixels around the target Red pixel to ensure
346 // they are the expected color values
Austin Kinrossfbd78202015-05-28 15:33:55 -0700347 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800348 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700349 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800350 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700351 // 1x1 is expected to be a red pixel
Cooper Partine6664f02015-01-09 16:22:24 -0800352 // All others are black
353 GLubyte expectedColor[4] = { 0, 0, 0, 0 };
Austin Kinrossfbd78202015-05-28 15:33:55 -0700354 if (x == 1 && y == 1)
Cooper Partine6664f02015-01-09 16:22:24 -0800355 {
356 expectedColor[0] = 255;
357 expectedColor[3] = 255;
358 }
359 EXPECT_PIXEL_EQ(x, y, expectedColor[0], expectedColor[1], expectedColor[2], expectedColor[3]);
360 }
361 }
362
Cooper Partine6664f02015-01-09 16:22:24 -0800363 GLfloat pointSizeRange[2] = {};
364 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
365
366 if (pointSizeRange[1] >= 2.0)
367 {
368 // Draw a point of size 2 and verify it fills the appropriate region.
369 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
370
371 glUniform1f(pointSizeLoc, 2.0f);
372 ASSERT_GL_NO_ERROR();
373
Corentin Wallez973402f2015-05-11 13:42:22 -0400374 glDrawArrays(GL_POINTS, 0, ArraySize(vertices) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800375 ASSERT_GL_NO_ERROR();
376
377 // Test the pixels to ensure the target is ALL Red pixels
Austin Kinrossfbd78202015-05-28 15:33:55 -0700378 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800379 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700380 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800381 {
382 EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
383 }
384 }
385 }
386
387 glDeleteBuffers(1, &vertexObject);
388}
Cooper Partin4e47b922015-02-03 09:04:20 -0800389
390// Verify that rendering works correctly when gl_PointSize is declared in a shader but isn't used
Jamie Madillfa05f602015-05-07 13:47:11 -0400391TEST_P(PointSpritesTest, PointSizeDeclaredButUnused)
Cooper Partin4e47b922015-02-03 09:04:20 -0800392{
393 const std::string vs = SHADER_SOURCE
394 (
395 attribute highp vec4 position;
396
397 void main(void)
398 {
399 gl_PointSize = 1.0;
400 gl_Position = position;
401 }
402 );
403
404 const std::string fs = SHADER_SOURCE
405 (
406 void main(void)
407 {
408 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
409 }
410 );
411
412 GLuint program = CompileProgram(vs, fs);
413 ASSERT_NE(program, 0u);
414 ASSERT_GL_NO_ERROR();
415
416 glUseProgram(program);
417 drawQuad(program, "position", 0.5f, 1.0f);
418 ASSERT_GL_NO_ERROR();
419
420 // expect the center pixel to be red
421 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
422
423 glDeleteProgram(program);
424}
Jamie Madillfa05f602015-05-07 13:47:11 -0400425
426// Use this to select which configurations (e.g. which renderer, which GLES
427// major version) these tests should be run against.
428//
429// We test on D3D11 9_3 because the existing D3D11 PointSprite implementation
430// uses Geometry Shaders which are not supported for 9_3.
431// D3D9 and D3D11 are also tested to ensure no regressions.
432ANGLE_INSTANTIATE_TEST(PointSpritesTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());