blob: a407616fe82b9f0bdb51054134f23a1f4771af76 [file] [log] [blame]
Jamie Madilld55d2832015-10-27 13:59:19 -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.
5//
6// ProvkingVertexTest:
7// Tests on the conformance of the provoking vertex, which applies to flat
8// shading and compatibility with D3D. See the section on 'flatshading'
9// in the ES 3 specs.
10//
11
12#include "test_utils/ANGLETest.h"
13
14using namespace angle;
15
16namespace
17{
18
19class ProvokingVertexTest : public ANGLETest
20{
21 protected:
22 ProvokingVertexTest()
23 : mProgram(0),
24 mFramebuffer(0),
25 mTexture(0),
26 mTransformFeedback(0),
27 mBuffer(0),
28 mIntAttribLocation(-1)
29 {
30 setWindowWidth(64);
31 setWindowHeight(64);
32 setConfigRedBits(8);
33 setConfigGreenBits(8);
34 setConfigBlueBits(8);
35 setConfigAlphaBits(8);
36 setConfigDepthBits(24);
37 }
38
39 void SetUp() override
40 {
41 ANGLETest::SetUp();
42
43 const std::string &vertexShader =
44 "#version 300 es\n"
45 "in int intAttrib;\n"
46 "in vec2 position;\n"
47 "flat out int attrib;\n"
48 "void main() {\n"
49 " gl_Position = vec4(position, 0, 1);\n"
50 " attrib = intAttrib;\n"
51 "}";
52
53 const std::string &fragmentShader =
54 "#version 300 es\n"
55 "flat in int attrib;\n"
56 "out int fragColor;\n"
57 "void main() {\n"
58 " fragColor = attrib;\n"
59 "}";
60
61 std::vector<std::string> tfVaryings;
62 tfVaryings.push_back("attrib");
63 mProgram = CompileProgramWithTransformFeedback(vertexShader, fragmentShader, tfVaryings,
64 GL_SEPARATE_ATTRIBS);
65 ASSERT_NE(0u, mProgram);
66
67 glGenTextures(1, &mTexture);
68 glBindTexture(GL_TEXTURE_2D, mTexture);
69 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, getWindowWidth(), getWindowHeight());
70
71 glGenFramebuffers(1, &mFramebuffer);
72 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
73 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
74
75 mIntAttribLocation = glGetAttribLocation(mProgram, "intAttrib");
76 ASSERT_NE(-1, mIntAttribLocation);
77 glEnableVertexAttribArray(mIntAttribLocation);
78
79 ASSERT_GL_NO_ERROR();
80 }
81
82 void TearDown() override
83 {
84 if (mProgram != 0)
85 {
86 glDeleteProgram(mProgram);
87 mProgram = 0;
88 }
89
90 if (mFramebuffer != 0)
91 {
92 glDeleteFramebuffers(1, &mFramebuffer);
93 mFramebuffer = 0;
94 }
95
96 if (mTexture != 0)
97 {
98 glDeleteTextures(1, &mTexture);
99 mTexture = 0;
100 }
101
102 if (mTransformFeedback != 0)
103 {
104 glDeleteTransformFeedbacks(1, &mTransformFeedback);
105 mTransformFeedback = 0;
106 }
107
108 if (mBuffer != 0)
109 {
110 glDeleteBuffers(1, &mBuffer);
111 mBuffer = 0;
112 }
113
114 ANGLETest::TearDown();
115 }
116
117 GLuint mProgram;
118 GLuint mFramebuffer;
119 GLuint mTexture;
120 GLuint mTransformFeedback;
121 GLuint mBuffer;
122 GLint mIntAttribLocation;
123};
124
125// Test drawing a simple triangle with flat shading, and different valued vertices.
126TEST_P(ProvokingVertexTest, FlatTriangle)
127{
Jamie Madilld55d2832015-10-27 13:59:19 -0400128 GLint vertexData[] = {1, 2, 3, 1, 2, 3};
129 glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
130
131 drawQuad(mProgram, "position", 0.5f);
132
133 GLint pixelValue = 0;
134 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_INT, &pixelValue);
135
136 ASSERT_GL_NO_ERROR();
137 EXPECT_EQ(vertexData[2], pixelValue);
138}
139
140// Ensure that any provoking vertex shenanigans still gives correct vertex streams.
141TEST_P(ProvokingVertexTest, FlatTriWithTransformFeedback)
142{
Corentin Wallezdd46e642016-01-20 15:13:10 -0500143 // TODO(cwallez) figure out why it is broken on AMD on Mac
144#if defined(ANGLE_PLATFORM_APPLE)
Jamie Madill518b9fa2016-03-02 11:26:02 -0500145 if (IsAMD())
Corentin Wallezdd46e642016-01-20 15:13:10 -0500146 {
147 std::cout << "Test skipped on AMD on Mac." << std::endl;
148 return;
149 }
150#endif
151
Jamie Madilld55d2832015-10-27 13:59:19 -0400152 glGenTransformFeedbacks(1, &mTransformFeedback);
153 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
154
155 glGenBuffers(1, &mBuffer);
156 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mBuffer);
157 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 128, nullptr, GL_STREAM_DRAW);
158
159 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mBuffer);
160
161 GLint vertexData[] = {1, 2, 3, 1, 2, 3};
162 glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
163
164 glBeginTransformFeedback(GL_TRIANGLES);
165 drawQuad(mProgram, "position", 0.5f);
166 glEndTransformFeedback();
167
168 GLint pixelValue = 0;
169 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_INT, &pixelValue);
170
171 ASSERT_GL_NO_ERROR();
172 EXPECT_EQ(vertexData[2], pixelValue);
173
174 GLvoid *mapPointer =
175 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(int) * 6, GL_MAP_READ_BIT);
176 ASSERT_NE(nullptr, mapPointer);
177
178 int *mappedInts = static_cast<int *>(mapPointer);
179 for (unsigned int cnt = 0; cnt < 6; ++cnt)
180 {
181 EXPECT_EQ(vertexData[cnt], mappedInts[cnt]);
182 }
183}
184
185// Test drawing a simple line with flat shading, and different valued vertices.
186TEST_P(ProvokingVertexTest, FlatLine)
187{
Jamie Madilld55d2832015-10-27 13:59:19 -0400188 GLfloat halfPixel = 1.0f / static_cast<GLfloat>(getWindowWidth());
189
190 GLint vertexData[] = {1, 2};
191 GLfloat positionData[] = {-1.0f + halfPixel, -1.0f, -1.0f + halfPixel, 1.0f};
192
193 glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
194
195 GLint positionLocation = glGetAttribLocation(mProgram, "position");
196 glEnableVertexAttribArray(positionLocation);
197 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
198
199 glUseProgram(mProgram);
200 glDrawArrays(GL_LINES, 0, 2);
201
202 GLint pixelValue = 0;
203 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_INT, &pixelValue);
204
205 ASSERT_GL_NO_ERROR();
206 EXPECT_EQ(vertexData[1], pixelValue);
207}
208
209// Test drawing a simple triangle strip with flat shading, and different valued vertices.
210TEST_P(ProvokingVertexTest, FlatTriStrip)
211{
Jamie Madilld55d2832015-10-27 13:59:19 -0400212 GLint vertexData[] = {1, 2, 3, 4, 5, 6};
213 GLfloat positionData[] = {-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, -1.0f,
214 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
215
216 glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
217
218 GLint positionLocation = glGetAttribLocation(mProgram, "position");
219 glEnableVertexAttribArray(positionLocation);
220 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
221
222 glUseProgram(mProgram);
223 glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
224
225 std::vector<GLint> pixelBuffer(getWindowWidth() * getWindowHeight(), 0);
226 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RED_INTEGER, GL_INT,
227 &pixelBuffer[0]);
228
229 ASSERT_GL_NO_ERROR();
230
231 for (unsigned int triIndex = 0; triIndex < 4; ++triIndex)
232 {
233 GLfloat sumX = positionData[triIndex * 2 + 0] + positionData[triIndex * 2 + 2] +
234 positionData[triIndex * 2 + 4];
235 GLfloat sumY = positionData[triIndex * 2 + 1] + positionData[triIndex * 2 + 3] +
236 positionData[triIndex * 2 + 5];
237
238 float centerX = sumX / 3.0f * 0.5f + 0.5f;
239 float centerY = sumY / 3.0f * 0.5f + 0.5f;
240 unsigned int pixelX =
241 static_cast<unsigned int>(centerX * static_cast<GLfloat>(getWindowWidth()));
242 unsigned int pixelY =
243 static_cast<unsigned int>(centerY * static_cast<GLfloat>(getWindowHeight()));
244 unsigned int pixelIndex = pixelY * getWindowWidth() + pixelX;
245
246 unsigned int provokingVertexIndex = triIndex + 2;
247
248 EXPECT_EQ(vertexData[provokingVertexIndex], pixelBuffer[pixelIndex]);
249 }
250}
251
252// Test drawing an indexed triangle strip with flat shading and primitive restart.
253TEST_P(ProvokingVertexTest, FlatTriStripPrimitiveRestart)
254{
255 // TODO(jmadill): Implement on the D3D back-end.
Jamie Madill518b9fa2016-03-02 11:26:02 -0500256 if (IsD3D11())
Jamie Madilld55d2832015-10-27 13:59:19 -0400257 {
258 std::cout << "Test disabled on D3D11." << std::endl;
259 return;
260 }
261
262 GLint indexData[] = {0, 1, 2, -1, 1, 2, 3, 4, -1, 3, 4, 5};
263 GLint vertexData[] = {1, 2, 3, 4, 5, 6};
264 GLfloat positionData[] = {-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, -1.0f,
265 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
266
267 glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
268
269 GLint positionLocation = glGetAttribLocation(mProgram, "position");
270 glEnableVertexAttribArray(positionLocation);
271 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
272
273 glDisable(GL_CULL_FACE);
274 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
275 glUseProgram(mProgram);
276 glDrawElements(GL_TRIANGLE_STRIP, 12, GL_UNSIGNED_INT, indexData);
277
278 std::vector<GLint> pixelBuffer(getWindowWidth() * getWindowHeight(), 0);
279 glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RED_INTEGER, GL_INT,
280 &pixelBuffer[0]);
281
282 ASSERT_GL_NO_ERROR();
283
284 // Account for primitive restart when checking the tris.
285 GLint triOffsets[] = {0, 4, 5, 9};
286
287 for (unsigned int triIndex = 0; triIndex < 4; ++triIndex)
288 {
289 GLint vertexA = indexData[triOffsets[triIndex] + 0];
290 GLint vertexB = indexData[triOffsets[triIndex] + 1];
291 GLint vertexC = indexData[triOffsets[triIndex] + 2];
292
293 GLfloat sumX =
294 positionData[vertexA * 2] + positionData[vertexB * 2] + positionData[vertexC * 2];
295 GLfloat sumY = positionData[vertexA * 2 + 1] + positionData[vertexB * 2 + 1] +
296 positionData[vertexC * 2 + 1];
297
298 float centerX = sumX / 3.0f * 0.5f + 0.5f;
299 float centerY = sumY / 3.0f * 0.5f + 0.5f;
300 unsigned int pixelX =
301 static_cast<unsigned int>(centerX * static_cast<GLfloat>(getWindowWidth()));
302 unsigned int pixelY =
303 static_cast<unsigned int>(centerY * static_cast<GLfloat>(getWindowHeight()));
304 unsigned int pixelIndex = pixelY * getWindowWidth() + pixelX;
305
306 unsigned int provokingVertexIndex = triIndex + 2;
307
308 EXPECT_EQ(vertexData[provokingVertexIndex], pixelBuffer[pixelIndex]);
309 }
310}
311
Geoff Lange0cc2a42016-01-20 10:58:17 -0500312ANGLE_INSTANTIATE_TEST(ProvokingVertexTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Jamie Madilld55d2832015-10-27 13:59:19 -0400313
314} // anonymous namespace