blob: b7bdc2d34b93f8894198eebc305972216f433312 [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
Jamie Madillfa05f602015-05-07 13:47:11 -04009#include "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
294 GLuint program = CompileProgram(vs, fs);
295 ASSERT_NE(program, 0u);
296 ASSERT_GL_NO_ERROR();
297
298 glUseProgram(program);
299
300 glDisable(GL_BLEND);
301
302 // The choice of (0.4, 0.4) ensures that the centers of the surrounding
303 // pixels are not contained within the point when it is of size 1, but
304 // that they definitely are when it is of size 2.
305 GLfloat vertices[] = { 0.4f, 0.4f, 0.0f };
306 GLubyte colors[] = { 255, 0, 0, 255 };
307
308 GLuint vertexObject = 0;
309 glGenBuffers(1, &vertexObject);
310 ASSERT_NE(vertexObject, 0U);
311 ASSERT_GL_NO_ERROR();
312
313 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
314 ASSERT_GL_NO_ERROR();
315
316 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
317 ASSERT_GL_NO_ERROR();
318
319 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
320 ASSERT_GL_NO_ERROR();
321
322 glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
323 ASSERT_GL_NO_ERROR();
324
325 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
326
327 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
328 glEnableVertexAttribArray(0);
329
330 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (GLvoid*)sizeof(vertices));
331 glEnableVertexAttribArray(1);
332
333 GLint pointSizeLoc = glGetUniformLocation(program, "pointSize");
334 ASSERT_GL_NO_ERROR();
335
336 glUniform1f(pointSizeLoc, 1.0f);
337 ASSERT_GL_NO_ERROR();
338
339 glDrawArrays(GL_POINTS, 0, _countof(vertices) / 3);
340 ASSERT_GL_NO_ERROR();
341
342 // Test the pixels around the target Red pixel to ensure
343 // they are the expected color values
344 for (GLint y = 178; y < 180; ++y)
345 {
346 for (GLint x = 178; x < 180; ++x)
347 {
348 // 179x179 is expected to be a red pixel
349 // All others are black
350 GLubyte expectedColor[4] = { 0, 0, 0, 0 };
351 if (x == 179 && y == 179)
352 {
353 expectedColor[0] = 255;
354 expectedColor[3] = 255;
355 }
356 EXPECT_PIXEL_EQ(x, y, expectedColor[0], expectedColor[1], expectedColor[2], expectedColor[3]);
357 }
358 }
359
360 swapBuffers();
361
362 GLfloat pointSizeRange[2] = {};
363 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
364
365 if (pointSizeRange[1] >= 2.0)
366 {
367 // Draw a point of size 2 and verify it fills the appropriate region.
368 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
369
370 glUniform1f(pointSizeLoc, 2.0f);
371 ASSERT_GL_NO_ERROR();
372
373 glDrawArrays(GL_POINTS, 0, _countof(vertices) / 3);
374 ASSERT_GL_NO_ERROR();
375
376 // Test the pixels to ensure the target is ALL Red pixels
377 for (GLint y = 178; y < 180; ++y)
378 {
379 for (GLint x = 178; x < 180; ++x)
380 {
381 EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
382 }
383 }
384 }
385
386 glDeleteBuffers(1, &vertexObject);
387}
Cooper Partin4e47b922015-02-03 09:04:20 -0800388
389// Verify that rendering works correctly when gl_PointSize is declared in a shader but isn't used
Jamie Madillfa05f602015-05-07 13:47:11 -0400390TEST_P(PointSpritesTest, PointSizeDeclaredButUnused)
Cooper Partin4e47b922015-02-03 09:04:20 -0800391{
392 const std::string vs = SHADER_SOURCE
393 (
394 attribute highp vec4 position;
395
396 void main(void)
397 {
398 gl_PointSize = 1.0;
399 gl_Position = position;
400 }
401 );
402
403 const std::string fs = SHADER_SOURCE
404 (
405 void main(void)
406 {
407 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
408 }
409 );
410
411 GLuint program = CompileProgram(vs, fs);
412 ASSERT_NE(program, 0u);
413 ASSERT_GL_NO_ERROR();
414
415 glUseProgram(program);
416 drawQuad(program, "position", 0.5f, 1.0f);
417 ASSERT_GL_NO_ERROR();
418
419 // expect the center pixel to be red
420 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
421
422 glDeleteProgram(program);
423}
Jamie Madillfa05f602015-05-07 13:47:11 -0400424
425// Use this to select which configurations (e.g. which renderer, which GLES
426// major version) these tests should be run against.
427//
428// We test on D3D11 9_3 because the existing D3D11 PointSprite implementation
429// uses Geometry Shaders which are not supported for 9_3.
430// D3D9 and D3D11 are also tested to ensure no regressions.
431ANGLE_INSTANTIATE_TEST(PointSpritesTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());