blob: 3bc565f6e60c75e50672b2a3ee03d3eb828b91c3 [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{
45 const std::string fs = SHADER_SOURCE
46 (
47 precision mediump float;
48 void main()
49 {
50 gl_FragColor = vec4(
51 gl_PointCoord.x,
52 gl_PointCoord.y,
53 0,
54 1);
55 }
56 );
57
58 const std::string vs = SHADER_SOURCE
59 (
60 attribute vec4 vPosition;
61 uniform float uPointSize;
62 void main()
63 {
64 gl_PointSize = uPointSize;
65 gl_Position = vPosition;
66 }
67 );
68
69 GLuint program = CompileProgram(vs, fs);
70 ASSERT_NE(program, 0u);
71 ASSERT_GL_NO_ERROR();
72
73 glUseProgram(program);
74
75 GLfloat pointSizeRange[2] = {};
76 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
77
78 GLfloat maxPointSize = pointSizeRange[1];
79
80 ASSERT_TRUE(maxPointSize >= 1);
81 maxPointSize = floorf(maxPointSize);
82 ASSERT_TRUE((int)maxPointSize % 1 == 0);
83
84 maxPointSize = std::min(maxPointSize, 64.0f);
85 GLfloat pointWidth = maxPointSize / windowWidth;
Minmin Gong794e0002015-04-07 18:31:54 -070086 GLint step = static_cast<GLint>(floorf(maxPointSize / 4));
87 GLint pointStep = std::max<GLint>(1, step);
Cooper Partine6664f02015-01-09 16:22:24 -080088
89 GLint pointSizeLoc = glGetUniformLocation(program, "uPointSize");
90 ASSERT_GL_NO_ERROR();
91
92 glUniform1f(pointSizeLoc, maxPointSize);
93 ASSERT_GL_NO_ERROR();
94
95 GLfloat pixelOffset = ((int)maxPointSize % 2) ? (1.0f / (GLfloat)windowWidth) : 0;
96 GLuint vertexObject = 0;
97 glGenBuffers(1, &vertexObject);
98 ASSERT_NE(vertexObject, 0U);
99 ASSERT_GL_NO_ERROR();
100
101 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
102 ASSERT_GL_NO_ERROR();
103
Minmin Gong794e0002015-04-07 18:31:54 -0700104 GLfloat thePoints[] = { -0.5f + pixelOffset, -0.5f + pixelOffset,
105 0.5f + pixelOffset, -0.5f + pixelOffset,
106 -0.5f + pixelOffset, 0.5f + pixelOffset,
107 0.5f + pixelOffset, 0.5f + pixelOffset };
Cooper Partine6664f02015-01-09 16:22:24 -0800108
109 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
110 ASSERT_GL_NO_ERROR();
111
112 glEnableVertexAttribArray(0);
113 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
114
115 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
116
117 glDrawArrays(GL_POINTS, 0, 4);
118 ASSERT_GL_NO_ERROR();
119
120 glDeleteBuffers(1, &vertexObject);
121
122 std::string debugText;
123 for (float py = 0; py < 2; ++py) {
124 for (float px = 0; px < 2; ++px) {
Minmin Gong794e0002015-04-07 18:31:54 -0700125 float pointX = -0.5f + px + pixelOffset;
126 float pointY = -0.5f + py + pixelOffset;
Cooper Partine6664f02015-01-09 16:22:24 -0800127 for (int yy = 0; yy < maxPointSize; yy += pointStep) {
128 for (int xx = 0; xx < maxPointSize; xx += pointStep) {
129 // formula for s and t from OpenGL ES 2.0 spec section 3.3
130 float xw = s2p(pointX);
131 float yw = s2p(pointY);
132 float u = xx / maxPointSize * 2 - 1;
133 float v = yy / maxPointSize * 2 - 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700134 int xf = static_cast<int>(floorf(s2p(pointX + u * pointWidth)));
135 int yf = static_cast<int>(floorf(s2p(pointY + v * pointWidth)));
136 float s = 0.5f + (xf + 0.5f - xw) / maxPointSize;
137 float t = 0.5f + (yf + 0.5f - yw) / maxPointSize;
138 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 -0800139 EXPECT_PIXEL_NEAR(xf, yf, color[0], color[1], color[2], color[3], 4);
140 }
141 }
142 }
143 }
144}
145
146// Verify that drawing a point without enabling any attributes succeeds
147// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-no-attributes.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400148TEST_P(PointSpritesTest, PointWithoutAttributesCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800149{
150 const std::string fs = SHADER_SOURCE
151 (
152 precision mediump float;
153 void main()
154 {
155 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
156 }
157 );
158
159 const std::string vs = SHADER_SOURCE
160 (
161 void main()
162 {
163 gl_PointSize = 1.0;
164 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
165 }
166 );
167
168 GLuint program = CompileProgram(vs, fs);
169 ASSERT_NE(program, 0u);
170 ASSERT_GL_NO_ERROR();
171
172 glUseProgram(program);
173
174 glDrawArrays(GL_POINTS, 0, 1);
175 ASSERT_GL_NO_ERROR();
176
177 // expect the center pixel to be green
178 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
179}
180
181// This is a regression test for a graphics driver bug affecting end caps on roads in MapsGL
182// 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 -0400183TEST_P(PointSpritesTest, PointCoordRegressionTest)
Cooper Partine6664f02015-01-09 16:22:24 -0800184{
185 const std::string fs = SHADER_SOURCE
186 (
187 precision mediump float;
188 varying vec4 v_color;
189 void main()
190 {
191 // It seems as long as this mathematical expression references
192 // gl_PointCoord, the fragment's color is incorrect.
193 vec2 diff = gl_PointCoord - vec2(.5, .5);
194 if (length(diff) > 0.5)
195 discard;
196
197 // The point should be a solid color.
198 gl_FragColor = v_color;
199 }
200 );
201
202 const std::string vs = SHADER_SOURCE
203 (
204 varying vec4 v_color;
205 // The X and Y coordinates of the center of the point.
206 attribute vec2 a_vertex;
207 uniform float u_pointSize;
208 void main()
209 {
210 gl_PointSize = u_pointSize;
211 gl_Position = vec4(a_vertex, 0.0, 1.0);
212 // The color of the point.
213 v_color = vec4(0.0, 1.0, 0.0, 1.0);
214 }
215 );
216
217 GLuint program = CompileProgram(vs, fs);
218 ASSERT_NE(program, 0u);
219 ASSERT_GL_NO_ERROR();
220
221 glUseProgram(program);
222
223 GLfloat pointSizeRange[2] = {};
224 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
225
226 GLfloat maxPointSize = pointSizeRange[1];
227
228 ASSERT_TRUE(maxPointSize > 2);
229
230 glClearColor(0, 0, 0, 1);
231 glDisable(GL_DEPTH_TEST);
232 glClear(GL_COLOR_BUFFER_BIT);
233
234 GLint pointSizeLoc = glGetUniformLocation(program, "u_pointSize");
235 ASSERT_GL_NO_ERROR();
236
237 GLfloat pointSize = std::min<GLfloat>(20.0f, maxPointSize);
238 glUniform1f(pointSizeLoc, pointSize);
239 ASSERT_GL_NO_ERROR();
240
241 GLuint vertexObject = 0;
242 glGenBuffers(1, &vertexObject);
243 ASSERT_NE(vertexObject, 0U);
244 ASSERT_GL_NO_ERROR();
245
246 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
247 ASSERT_GL_NO_ERROR();
248
249 GLfloat thePoints[] = { 0.0f, 0.0f };
250
251 glBufferData(GL_ARRAY_BUFFER, sizeof(thePoints), thePoints, GL_STATIC_DRAW);
252 ASSERT_GL_NO_ERROR();
253
254 glEnableVertexAttribArray(0);
255 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
256
257 glDrawArrays(GL_POINTS, 0, 1);
258 ASSERT_GL_NO_ERROR();
259
260 // expect the center pixel to be green
261 EXPECT_PIXEL_EQ((windowWidth - 1) / 2, (windowHeight - 1) / 2, 0, 255, 0, 255);
262
263 glDeleteBuffers(1, &vertexObject);
264}
265
266// Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled
267// https://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/point-size.html
Jamie Madillfa05f602015-05-07 13:47:11 -0400268TEST_P(PointSpritesTest, PointSizeEnabledCompliance)
Cooper Partine6664f02015-01-09 16:22:24 -0800269{
270 const std::string fs = SHADER_SOURCE
271 (
272 precision mediump float;
273 varying vec4 color;
274
275 void main()
276 {
277 gl_FragColor = color;
278 }
279 );
280
281 const std::string vs = SHADER_SOURCE
282 (
283 attribute vec3 pos;
284 attribute vec4 colorIn;
285 uniform float pointSize;
286 varying vec4 color;
287
288 void main()
289 {
290 gl_PointSize = pointSize;
291 color = colorIn;
292 gl_Position = vec4(pos, 1.0);
293 }
294 );
295
Austin Kinrossfbd78202015-05-28 15:33:55 -0700296 // The WebGL test is drawn on a 2x2 canvas. Emulate this by setting a 2x2 viewport.
297 glViewport(0, 0, 2, 2);
298
Cooper Partine6664f02015-01-09 16:22:24 -0800299 GLuint program = CompileProgram(vs, fs);
300 ASSERT_NE(program, 0u);
301 ASSERT_GL_NO_ERROR();
302
303 glUseProgram(program);
304
305 glDisable(GL_BLEND);
306
307 // The choice of (0.4, 0.4) ensures that the centers of the surrounding
308 // pixels are not contained within the point when it is of size 1, but
309 // that they definitely are when it is of size 2.
310 GLfloat vertices[] = { 0.4f, 0.4f, 0.0f };
311 GLubyte colors[] = { 255, 0, 0, 255 };
312
313 GLuint vertexObject = 0;
314 glGenBuffers(1, &vertexObject);
315 ASSERT_NE(vertexObject, 0U);
316 ASSERT_GL_NO_ERROR();
317
318 glBindBuffer(GL_ARRAY_BUFFER, vertexObject);
319 ASSERT_GL_NO_ERROR();
320
321 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
322 ASSERT_GL_NO_ERROR();
323
324 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
325 ASSERT_GL_NO_ERROR();
326
327 glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
328 ASSERT_GL_NO_ERROR();
329
330 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
331
332 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
333 glEnableVertexAttribArray(0);
334
335 glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (GLvoid*)sizeof(vertices));
336 glEnableVertexAttribArray(1);
337
338 GLint pointSizeLoc = glGetUniformLocation(program, "pointSize");
339 ASSERT_GL_NO_ERROR();
340
341 glUniform1f(pointSizeLoc, 1.0f);
342 ASSERT_GL_NO_ERROR();
343
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700344 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800345 ASSERT_GL_NO_ERROR();
346
347 // Test the pixels around the target Red pixel to ensure
348 // they are the expected color values
Austin Kinrossfbd78202015-05-28 15:33:55 -0700349 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800350 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700351 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800352 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700353 // 1x1 is expected to be a red pixel
Cooper Partine6664f02015-01-09 16:22:24 -0800354 // All others are black
355 GLubyte expectedColor[4] = { 0, 0, 0, 0 };
Austin Kinrossfbd78202015-05-28 15:33:55 -0700356 if (x == 1 && y == 1)
Cooper Partine6664f02015-01-09 16:22:24 -0800357 {
358 expectedColor[0] = 255;
359 expectedColor[3] = 255;
360 }
361 EXPECT_PIXEL_EQ(x, y, expectedColor[0], expectedColor[1], expectedColor[2], expectedColor[3]);
362 }
363 }
364
Cooper Partine6664f02015-01-09 16:22:24 -0800365 GLfloat pointSizeRange[2] = {};
366 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
367
368 if (pointSizeRange[1] >= 2.0)
369 {
370 // Draw a point of size 2 and verify it fills the appropriate region.
371 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
372
373 glUniform1f(pointSizeLoc, 2.0f);
374 ASSERT_GL_NO_ERROR();
375
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700376 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(ArraySize(vertices)) / 3);
Cooper Partine6664f02015-01-09 16:22:24 -0800377 ASSERT_GL_NO_ERROR();
378
379 // Test the pixels to ensure the target is ALL Red pixels
Austin Kinrossfbd78202015-05-28 15:33:55 -0700380 for (GLint y = 0; y < 2; ++y)
Cooper Partine6664f02015-01-09 16:22:24 -0800381 {
Austin Kinrossfbd78202015-05-28 15:33:55 -0700382 for (GLint x = 0; x < 2; ++x)
Cooper Partine6664f02015-01-09 16:22:24 -0800383 {
384 EXPECT_PIXEL_EQ(x, y, 255, 0, 0, 255);
385 }
386 }
387 }
388
389 glDeleteBuffers(1, &vertexObject);
390}
Cooper Partin4e47b922015-02-03 09:04:20 -0800391
392// Verify that rendering works correctly when gl_PointSize is declared in a shader but isn't used
Jamie Madillfa05f602015-05-07 13:47:11 -0400393TEST_P(PointSpritesTest, PointSizeDeclaredButUnused)
Cooper Partin4e47b922015-02-03 09:04:20 -0800394{
395 const std::string vs = SHADER_SOURCE
396 (
397 attribute highp vec4 position;
398
399 void main(void)
400 {
401 gl_PointSize = 1.0;
402 gl_Position = position;
403 }
404 );
405
406 const std::string fs = SHADER_SOURCE
407 (
408 void main(void)
409 {
410 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
411 }
412 );
413
414 GLuint program = CompileProgram(vs, fs);
415 ASSERT_NE(program, 0u);
416 ASSERT_GL_NO_ERROR();
417
418 glUseProgram(program);
419 drawQuad(program, "position", 0.5f, 1.0f);
420 ASSERT_GL_NO_ERROR();
421
422 // expect the center pixel to be red
423 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
424
425 glDeleteProgram(program);
426}
Jamie Madillfa05f602015-05-07 13:47:11 -0400427
428// Use this to select which configurations (e.g. which renderer, which GLES
429// major version) these tests should be run against.
430//
431// We test on D3D11 9_3 because the existing D3D11 PointSprite implementation
432// uses Geometry Shaders which are not supported for 9_3.
433// D3D9 and D3D11 are also tested to ensure no regressions.
Geoff Lang3cca86b2015-07-23 19:30:46 +0000434ANGLE_INSTANTIATE_TEST(PointSpritesTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());