1 //
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
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9 #include "util/EGLWindow.h"
10 #include "util/gles_loader_autogen.h"
11 #include "util/random_utils.h"
12 #include "util/test_utils.h"
13
14 using namespace angle;
15
16 namespace
17 {
18
19 class TransformFeedbackTestBase : public ANGLETest
20 {
21 protected:
TransformFeedbackTestBase()22 TransformFeedbackTestBase() : mProgram(0), mTransformFeedbackBuffer(0), mTransformFeedback(0)
23 {
24 setWindowWidth(48);
25 setWindowHeight(32);
26 setConfigRedBits(8);
27 setConfigGreenBits(8);
28 setConfigBlueBits(8);
29 setConfigAlphaBits(8);
30 }
31
testSetUp()32 void testSetUp() override
33 {
34 glGenBuffers(1, &mTransformFeedbackBuffer);
35 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
36 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, nullptr,
37 GL_STATIC_DRAW);
38
39 glGenTransformFeedbacks(1, &mTransformFeedback);
40
41 ASSERT_GL_NO_ERROR();
42 }
43
testTearDown()44 void testTearDown() override
45 {
46 if (mProgram != 0)
47 {
48 glDeleteProgram(mProgram);
49 mProgram = 0;
50 }
51
52 if (mTransformFeedbackBuffer != 0)
53 {
54 glDeleteBuffers(1, &mTransformFeedbackBuffer);
55 mTransformFeedbackBuffer = 0;
56 }
57
58 if (mTransformFeedback != 0)
59 {
60 glDeleteTransformFeedbacks(1, &mTransformFeedback);
61 mTransformFeedback = 0;
62 }
63 }
64
65 GLuint mProgram;
66
67 static const size_t mTransformFeedbackBufferSize = 1 << 24;
68 GLuint mTransformFeedbackBuffer;
69 GLuint mTransformFeedback;
70 };
71
72 class TransformFeedbackTest : public TransformFeedbackTestBase
73 {
74 protected:
compileDefaultProgram(const std::vector<std::string> & tfVaryings,GLenum bufferMode)75 void compileDefaultProgram(const std::vector<std::string> &tfVaryings, GLenum bufferMode)
76 {
77 ASSERT_EQ(0u, mProgram);
78
79 mProgram = CompileProgramWithTransformFeedback(
80 essl1_shaders::vs::Simple(), essl1_shaders::fs::Red(), tfVaryings, bufferMode);
81 ASSERT_NE(0u, mProgram);
82 }
83
84 void setupOverrunTest(const std::vector<GLfloat> &vertices);
85
86 void midRecordOpDoesNotContributeTest(std::function<void()> op);
87 };
88
89 // Test that using a transform feedback program without transform feedback active works, and that
90 // using it with transform feedback afterwards also works.
TEST_P(TransformFeedbackTest,NoCaptureThenCapture)91 TEST_P(TransformFeedbackTest, NoCaptureThenCapture)
92 {
93 constexpr char kFS[] = R"(#version 300 es
94 out mediump vec4 color;
95 void main()
96 {
97 color = vec4(0.6, 0.0, 0.0, 1.0);
98 })";
99
100 // Set the program's transform feedback varyings (just gl_Position)
101 std::vector<std::string> tfVaryings;
102 tfVaryings.push_back("gl_Position");
103 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(drawColor, essl3_shaders::vs::Simple(), kFS, tfVaryings,
104 GL_INTERLEAVED_ATTRIBS);
105
106 glUseProgram(drawColor);
107 GLint positionLocation = glGetAttribLocation(drawColor, essl3_shaders::PositionAttrib());
108 ASSERT_NE(positionLocation, -1);
109
110 const GLfloat vertices[] = {
111 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
112 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
113 };
114
115 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
116 glEnableVertexAttribArray(positionLocation);
117
118 glClearColor(0, 0, 0, 0);
119 glClear(GL_COLOR_BUFFER_BIT);
120
121 glEnable(GL_BLEND);
122 glBlendFunc(GL_ONE, GL_ONE);
123
124 GLQuery primitivesWrittenQuery;
125 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
126 ASSERT_GL_NO_ERROR();
127
128 // Don't bind a buffer for transform feedback output and don't activate transform feedback.
129 glDrawArrays(GL_TRIANGLES, 0, 6);
130
131 // Draw again, with xfb capture enabled.
132 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
133 glBeginTransformFeedback(GL_TRIANGLES);
134 glDrawArrays(GL_TRIANGLES, 0, 6);
135 glEndTransformFeedback();
136
137 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
138
139 // Ensure that both draw calls succeed.
140 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
141 EXPECT_GL_NO_ERROR();
142
143 GLuint primitivesWritten = 0;
144 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
145
146 // Ensure that only one draw call produced transform feedback data.
147 EXPECT_EQ(2u, primitivesWritten);
148 EXPECT_GL_NO_ERROR();
149
150 // Ensure that triangles were actually captured.
151 void *mappedBuffer =
152 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 24, GL_MAP_READ_BIT);
153 ASSERT_NE(nullptr, mappedBuffer);
154
155 const GLfloat expect[] = {
156 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
157 -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
158 };
159
160 float *mappedFloats = static_cast<float *>(mappedBuffer);
161 for (uint32_t i = 0; i < 24; ++i)
162 {
163 EXPECT_EQ(mappedFloats[i], expect[i]);
164 }
165 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
166
167 EXPECT_GL_NO_ERROR();
168 }
169
TEST_P(TransformFeedbackTest,ZeroSizedViewport)170 TEST_P(TransformFeedbackTest, ZeroSizedViewport)
171 {
172 // http://anglebug.com/5154
173 ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
174
175 // Set the program's transform feedback varyings (just gl_Position)
176 std::vector<std::string> tfVaryings;
177 tfVaryings.push_back("gl_Position");
178 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
179
180 glUseProgram(mProgram);
181
182 // Bind the buffer for transform feedback output and start transform feedback
183 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
184 glBeginTransformFeedback(GL_TRIANGLES);
185
186 // Create a query to check how many primitives were written
187 GLQuery primitivesWrittenQuery;
188 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
189
190 // Set a viewport that would result in no pixels being written to the framebuffer and draw
191 // a quad
192 glViewport(0, 0, 0, 0);
193
194 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
195
196 // End the query and transform feedback
197 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
198 glEndTransformFeedback();
199
200 glUseProgram(0);
201
202 // Check how many primitives were written and verify that some were written even if
203 // no pixels were rendered
204 GLuint primitivesWritten = 0;
205 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
206 EXPECT_GL_NO_ERROR();
207
208 EXPECT_EQ(2u, primitivesWritten);
209 }
210
211 // Test that using a transform feedback query in the following scenario doesn't crash:
212 //
213 // - Enable xfb query
214 // - Draw without xfb
215 // - Begin xfb
216 // - End xfb
217 // - End xfb query
218 //
TEST_P(TransformFeedbackTest,QueryActiveNoXfbDrawThenXfbBeginEnd)219 TEST_P(TransformFeedbackTest, QueryActiveNoXfbDrawThenXfbBeginEnd)
220 {
221 // Set the program's transform feedback varyings (just gl_Position)
222 std::vector<std::string> tfVaryings;
223 tfVaryings.push_back("gl_Position");
224 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(drawColor, essl3_shaders::vs::Simple(),
225 essl3_shaders::fs::Red(), tfVaryings,
226 GL_INTERLEAVED_ATTRIBS);
227
228 glUseProgram(drawColor);
229
230 GLQuery primitivesWrittenQuery;
231 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
232 ASSERT_GL_NO_ERROR();
233
234 drawQuad(drawColor, essl3_shaders::PositionAttrib(), 0.5f);
235
236 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
237 glBeginTransformFeedback(GL_TRIANGLES);
238 glEndTransformFeedback();
239
240 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
241
242 // Check that no primitives were written.
243 GLuint primitivesWritten = 0;
244 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
245 EXPECT_GL_NO_ERROR();
246
247 EXPECT_EQ(primitivesWritten, 0u);
248 }
249
250 // Test that rebinding a buffer with the same offset resets the offset (no longer appending from the
251 // old position)
TEST_P(TransformFeedbackTest,BufferRebinding)252 TEST_P(TransformFeedbackTest, BufferRebinding)
253 {
254 // http://anglebug.com/5154
255 ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
256
257 glDisable(GL_DEPTH_TEST);
258
259 // Set the program's transform feedback varyings (just gl_Position)
260 std::vector<std::string> tfVaryings;
261 tfVaryings.push_back("gl_Position");
262 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
263
264 glUseProgram(mProgram);
265
266 // Make sure the buffer has zero'd data
267 std::vector<float> data(mTransformFeedbackBufferSize / sizeof(float), 0.0f);
268 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
269 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
270 GL_STATIC_DRAW);
271
272 // Create a query to check how many primitives were written
273 GLQuery primitivesWrittenQuery;
274 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
275
276 const float finalZ = 0.95f;
277
278 RNG rng;
279
280 const size_t loopCount = 64;
281 for (size_t loopIdx = 0; loopIdx < loopCount; loopIdx++)
282 {
283 // Bind the buffer for transform feedback output and start transform feedback
284 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
285 glBeginTransformFeedback(GL_TRIANGLES);
286
287 float z = (loopIdx + 1 == loopCount) ? finalZ : rng.randomFloatBetween(0.1f, 0.5f);
288 drawQuad(mProgram, essl1_shaders::PositionAttrib(), z);
289
290 glEndTransformFeedback();
291 }
292
293 // End the query and transform feedback
294 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
295
296 glUseProgram(0);
297
298 // Check how many primitives were written and verify that some were written even if
299 // no pixels were rendered
300 GLuint primitivesWritten = 0;
301 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
302 EXPECT_GL_NO_ERROR();
303
304 EXPECT_EQ(loopCount * 2, primitivesWritten);
305
306 // Check the buffer data
307 const float *bufferData = static_cast<float *>(glMapBufferRange(
308 GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBufferSize, GL_MAP_READ_BIT));
309
310 for (size_t vertexIdx = 0; vertexIdx < 6; vertexIdx++)
311 {
312 // Check the third (Z) component of each vertex written and make sure it has the final
313 // value
314 EXPECT_NEAR(finalZ, bufferData[vertexIdx * 4 + 2], 0.0001);
315 }
316
317 for (size_t dataIdx = 24; dataIdx < mTransformFeedbackBufferSize / sizeof(float); dataIdx++)
318 {
319 EXPECT_EQ(data[dataIdx], bufferData[dataIdx]) << "Buffer overrun detected.";
320 }
321
322 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
323
324 EXPECT_GL_NO_ERROR();
325 }
326
327 // Test that XFB can write back vertices to a buffer and that we can draw from this buffer
328 // afterward.
TEST_P(TransformFeedbackTest,RecordAndDraw)329 TEST_P(TransformFeedbackTest, RecordAndDraw)
330 {
331 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
332 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
333
334 // Fails on Mac GL drivers. http://anglebug.com/4992
335 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
336
337 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
338 glClear(GL_COLOR_BUFFER_BIT);
339
340 // Set the program's transform feedback varyings (just gl_Position)
341 std::vector<std::string> tfVaryings;
342 tfVaryings.push_back("gl_Position");
343 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
344
345 glUseProgram(mProgram);
346
347 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
348
349 // First pass: draw 6 points to the XFB buffer
350 glEnable(GL_RASTERIZER_DISCARD);
351
352 const GLfloat vertices[] = {
353 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
354 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
355 };
356
357 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
358 glEnableVertexAttribArray(positionLocation);
359
360 // Bind the buffer for transform feedback output and start transform feedback
361 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
362 glBeginTransformFeedback(GL_POINTS);
363
364 // Create a query to check how many primitives were written
365 GLQuery primitivesWrittenQuery;
366 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
367
368 glDrawArrays(GL_POINTS, 0, 6);
369
370 glDisableVertexAttribArray(positionLocation);
371 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
372 // End the query and transform feedback
373 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
374 glEndTransformFeedback();
375
376 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
377
378 glDisable(GL_RASTERIZER_DISCARD);
379
380 // Check how many primitives were written and verify that some were written even if
381 // no pixels were rendered
382 GLuint primitivesWritten = 0;
383 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
384 EXPECT_GL_NO_ERROR();
385
386 EXPECT_EQ(6u, primitivesWritten);
387
388 // Nothing should have been drawn to the framebuffer
389 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 0);
390
391 // Second pass: draw from the feedback buffer
392
393 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
394 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
395 glEnableVertexAttribArray(positionLocation);
396
397 glDrawArrays(GL_TRIANGLES, 0, 6);
398
399 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
400 EXPECT_GL_NO_ERROR();
401 }
402
403 // Test that transform feedback can cover multiple render passes.
TEST_P(TransformFeedbackTest,SpanMultipleRenderPasses)404 TEST_P(TransformFeedbackTest, SpanMultipleRenderPasses)
405 {
406
407 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
408 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
409
410 // Fails on Mac GL drivers. http://anglebug.com/4992
411 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
412
413 // anglebug.com/5429
414 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
415
416 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
417 glClear(GL_COLOR_BUFFER_BIT);
418
419 // Set the program's transform feedback varyings (just gl_Position)
420 std::vector<std::string> tfVaryings;
421 tfVaryings.push_back("gl_Position");
422 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
423
424 glUseProgram(mProgram);
425
426 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
427
428 const GLfloat vertices[] = {
429 -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
430 -0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
431 };
432
433 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
434 glEnableVertexAttribArray(positionLocation);
435
436 // Bind the buffer for transform feedback output and start transform feedback
437 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
438 glBeginTransformFeedback(GL_POINTS);
439
440 // Create a query to check how many primitives were written
441 GLQuery primitivesWrittenQuery;
442 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
443
444 // Draw the first set of three points
445 glDrawArrays(GL_POINTS, 0, 3);
446
447 // Break the render pass
448 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
449
450 // Draw the second set of three points
451 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices + 9);
452 glDrawArrays(GL_POINTS, 0, 3);
453
454 glDisableVertexAttribArray(positionLocation);
455 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
456 // End the query and transform feedback
457 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
458 glEndTransformFeedback();
459
460 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
461
462 // Verify the number of primitives written
463 GLuint primitivesWritten = 0;
464 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
465 EXPECT_GL_NO_ERROR();
466
467 EXPECT_EQ(6u, primitivesWritten);
468
469 // Verify the captured buffer.
470
471 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
472 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
473 glEnableVertexAttribArray(positionLocation);
474
475 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
476 glClear(GL_COLOR_BUFFER_BIT);
477 glDrawArrays(GL_TRIANGLES, 0, 6);
478
479 const int w = getWindowWidth();
480 const int h = getWindowHeight();
481
482 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
483 EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::black);
484 EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::black);
485 EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::black);
486
487 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, h / 4 + 1, GLColor::red);
488 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, h / 4 + 1, GLColor::red);
489 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, 3 * h / 4 - 1, GLColor::red);
490 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, 3 * h / 4 - 1, GLColor::red);
491
492 EXPECT_PIXEL_COLOR_EQ(w / 2, h / 2, GLColor::red);
493
494 EXPECT_GL_NO_ERROR();
495 }
496
497 // Test that uploading data to buffer that's in use then using it for transform feedback works.
TEST_P(TransformFeedbackTest,UseAsUBOThenUpdateThenCapture)498 TEST_P(TransformFeedbackTest, UseAsUBOThenUpdateThenCapture)
499 {
500 // http://anglebug.com/5833
501 ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
502
503 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
504 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
505
506 // Fails on Mac GL drivers. http://anglebug.com/4992
507 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
508
509 const std::array<uint32_t, 12> kInitialData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
510 const std::array<uint32_t, 12> kUpdateData = {
511 0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u, 0x23456781u, 0xABCDEF09u,
512 0x3579BDF1u, 0x468ACE02u, 0x34567812u, 0xBCDEF09Au, 0x579BDF13u, 0x68ACE024u,
513 };
514
515 GLBuffer buffer;
516 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
517 glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);
518 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
519 EXPECT_GL_NO_ERROR();
520
521 constexpr char kVerifyUBO[] = R"(#version 300 es
522 precision mediump float;
523 uniform block {
524 uvec4 data[3];
525 } ubo;
526 out vec4 colorOut;
527 void main()
528 {
529 bool data0Ok = all(equal(ubo.data[0], uvec4(0, 1, 2, 3)));
530 bool data1Ok = all(equal(ubo.data[1], uvec4(4, 5, 6, 7)));
531 bool data2Ok = all(equal(ubo.data[2], uvec4(8, 9, 10, 11)));
532 if (data0Ok && data1Ok && data2Ok)
533 colorOut = vec4(0, 1.0, 0, 1.0);
534 else
535 colorOut = vec4(0, 0, 1.0, 1.0);
536 })";
537
538 ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);
539 drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
540 EXPECT_GL_NO_ERROR();
541
542 // Update buffer data
543 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData), kUpdateData.data());
544 EXPECT_GL_NO_ERROR();
545
546 // Set the program's transform feedback varyings (just gl_Position)
547 std::vector<std::string> tfVaryings;
548 tfVaryings.push_back("gl_Position");
549 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
550
551 glUseProgram(mProgram);
552
553 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
554
555 // First pass: draw 3 points to the XFB buffer
556 glEnable(GL_RASTERIZER_DISCARD);
557
558 const GLfloat vertices[] = {
559 -1.0f, 3.0f, 0.5f, -1.0f, -1.0f, 0.5f, 3.0f, -1.0f, 0.5f,
560 };
561
562 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
563 glEnableVertexAttribArray(positionLocation);
564
565 // Bind the buffer for transform feedback output and start transform feedback
566 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
567 glBeginTransformFeedback(GL_POINTS);
568
569 glDrawArrays(GL_POINTS, 0, 3);
570
571 glDisableVertexAttribArray(positionLocation);
572 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
573 glEndTransformFeedback();
574
575 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
576
577 glDisable(GL_RASTERIZER_DISCARD);
578
579 // Second pass: draw from the feedback buffer
580 glBindBuffer(GL_ARRAY_BUFFER, buffer);
581 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
582 glEnableVertexAttribArray(positionLocation);
583
584 glEnable(GL_BLEND);
585 glBlendFunc(GL_ONE, GL_ONE);
586 glDrawArrays(GL_TRIANGLES, 0, 3);
587 EXPECT_GL_NO_ERROR();
588
589 // Make sure both draws succeeded
590 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::yellow);
591 }
592
midRecordOpDoesNotContributeTest(std::function<void ()> op)593 void TransformFeedbackTest::midRecordOpDoesNotContributeTest(std::function<void()> op)
594 {
595 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
596 glClear(GL_COLOR_BUFFER_BIT);
597
598 // Set the program's transform feedback varyings (just gl_Position)
599 std::vector<std::string> tfVaryings;
600 tfVaryings.push_back("gl_Position");
601 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
602
603 glUseProgram(mProgram);
604
605 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
606
607 const GLfloat vertices[] = {
608 -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
609 -0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
610 };
611
612 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
613 glEnableVertexAttribArray(positionLocation);
614
615 // Bind the buffer for transform feedback output and start transform feedback
616 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
617 glBeginTransformFeedback(GL_POINTS);
618
619 // Create a query to check how many primitives were written
620 GLQuery primitivesWrittenQuery;
621 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
622
623 // Draw the first set of three points
624 glDrawArrays(GL_POINTS, 0, 3);
625
626 // Perform the operation in the middle of recording
627 op();
628
629 // Draw the second set of three points
630 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices + 9);
631 glDrawArrays(GL_POINTS, 0, 3);
632
633 glDisableVertexAttribArray(positionLocation);
634 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
635 // End the query and transform feedback
636 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
637 glEndTransformFeedback();
638
639 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
640
641 // Verify the number of primitives written
642 GLuint primitivesWritten = 0;
643 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
644 EXPECT_GL_NO_ERROR();
645
646 EXPECT_EQ(6u, primitivesWritten);
647
648 // Verify the captured buffer.
649 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
650 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
651 glEnableVertexAttribArray(positionLocation);
652
653 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
654 glClear(GL_COLOR_BUFFER_BIT);
655 glDrawArrays(GL_TRIANGLES, 0, 6);
656 }
657
658 // Test that draw-based clear between draws does not contribute to transform feedback.
TEST_P(TransformFeedbackTest,ClearWhileRecordingDoesNotContribute)659 TEST_P(TransformFeedbackTest, ClearWhileRecordingDoesNotContribute)
660 {
661
662 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
663 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
664
665 // Fails on Mac GL drivers. http://anglebug.com/4992
666 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
667
668 // anglebug.com/5434
669 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
670
671 auto clear = []() {
672 glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
673 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
674 glClear(GL_COLOR_BUFFER_BIT);
675 glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE);
676 };
677
678 midRecordOpDoesNotContributeTest(clear);
679
680 const int w = getWindowWidth();
681 const int h = getWindowHeight();
682
683 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
684 EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::blue);
685 EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::blue);
686 EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::blue);
687
688 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, h / 4 + 1, GLColor::magenta);
689 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, h / 4 + 1, GLColor::magenta);
690 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, 3 * h / 4 - 1, GLColor::magenta);
691 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, 3 * h / 4 - 1, GLColor::magenta);
692
693 EXPECT_PIXEL_COLOR_EQ(w / 2, h / 2, GLColor::magenta);
694
695 EXPECT_GL_NO_ERROR();
696 }
697
698 // Test that copy in the middle of rendering doesn't contribute to transform feedback.
TEST_P(TransformFeedbackTest,CopyWhileRecordingDoesNotContribute)699 TEST_P(TransformFeedbackTest, CopyWhileRecordingDoesNotContribute)
700 {
701
702 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
703 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
704
705 // Fails on Mac GL drivers. http://anglebug.com/4992
706 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
707
708 // anglebug.com/5434
709 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
710
711 auto copy = []() {
712 GLTexture texture;
713 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
714 };
715
716 midRecordOpDoesNotContributeTest(copy);
717
718 const int w = getWindowWidth();
719 const int h = getWindowHeight();
720
721 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
722 EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::black);
723 EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::black);
724 EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::black);
725
726 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, h / 4 + 1, GLColor::red);
727 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, h / 4 + 1, GLColor::red);
728 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, 3 * h / 4 - 1, GLColor::red);
729 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, 3 * h / 4 - 1, GLColor::red);
730
731 EXPECT_PIXEL_COLOR_EQ(w / 2, h / 2, GLColor::red);
732
733 EXPECT_GL_NO_ERROR();
734 }
735
736 // Test that blit in the middle of rendering doesn't contribute to transform feedback.
TEST_P(TransformFeedbackTest,BlitWhileRecordingDoesNotContribute)737 TEST_P(TransformFeedbackTest, BlitWhileRecordingDoesNotContribute)
738 {
739 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
740 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
741
742 // Fails on Mac GL drivers. http://anglebug.com/4992
743 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
744
745 // anglebug.com/5434
746 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
747
748 auto blit = []() {
749 GLFramebuffer dstFbo;
750 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
751
752 GLTexture dstTex;
753 glBindTexture(GL_TEXTURE_2D, dstTex);
754 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
755 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
756
757 glBlitFramebuffer(0, 0, 1, 1, 1, 1, 0, 0, GL_COLOR_BUFFER_BIT, GL_LINEAR);
758
759 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
760 };
761
762 midRecordOpDoesNotContributeTest(blit);
763
764 const int w = getWindowWidth();
765 const int h = getWindowHeight();
766
767 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
768 EXPECT_PIXEL_COLOR_EQ(w - 1, 0, GLColor::black);
769 EXPECT_PIXEL_COLOR_EQ(0, h - 1, GLColor::black);
770 EXPECT_PIXEL_COLOR_EQ(w - 1, h - 1, GLColor::black);
771
772 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, h / 4 + 1, GLColor::red);
773 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, h / 4 + 1, GLColor::red);
774 EXPECT_PIXEL_COLOR_EQ(w / 4 + 1, 3 * h / 4 - 1, GLColor::red);
775 EXPECT_PIXEL_COLOR_EQ(3 * w / 4 - 1, 3 * h / 4 - 1, GLColor::red);
776
777 EXPECT_PIXEL_COLOR_EQ(w / 2, h / 2, GLColor::red);
778
779 EXPECT_GL_NO_ERROR();
780 }
781
782 // Test that XFB does not allow writing more vertices than fit in the bound buffers.
783 // TODO(jmadill): Enable this test after fixing the last case where the buffer size changes after
784 // calling glBeginTransformFeedback.
TEST_P(TransformFeedbackTest,DISABLED_TooSmallBuffers)785 TEST_P(TransformFeedbackTest, DISABLED_TooSmallBuffers)
786 {
787 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
788 glClear(GL_COLOR_BUFFER_BIT);
789 glEnable(GL_RASTERIZER_DISCARD);
790
791 // Set the program's transform feedback varyings (just gl_Position)
792 std::vector<std::string> tfVaryings;
793 tfVaryings.push_back("gl_Position");
794 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
795 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
796
797 glUseProgram(mProgram);
798
799 const GLfloat vertices[] = {
800 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
801
802 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
803 };
804
805 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
806 glEnableVertexAttribArray(positionLocation);
807
808 const size_t verticesToDraw = 6;
809 const size_t stride = sizeof(float) * 4;
810 const size_t bytesNeeded = stride * verticesToDraw;
811
812 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
813
814 // Set up the buffer to be the right size
815 uint8_t tfData[stride * verticesToDraw] = {0};
816 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bytesNeeded, &tfData, GL_STATIC_DRAW);
817
818 glBeginTransformFeedback(GL_POINTS);
819 glDrawArrays(GL_POINTS, 0, verticesToDraw);
820 EXPECT_GL_NO_ERROR();
821 glEndTransformFeedback();
822
823 // Set up the buffer to be too small
824 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bytesNeeded - 1, &tfData, GL_STATIC_DRAW);
825
826 glBeginTransformFeedback(GL_POINTS);
827 EXPECT_GL_NO_ERROR();
828 glDrawArrays(GL_POINTS, 0, verticesToDraw);
829 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
830 glEndTransformFeedback();
831
832 // Set up the buffer to be the right size but make it smaller after glBeginTransformFeedback
833 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bytesNeeded, &tfData, GL_STATIC_DRAW);
834 glBeginTransformFeedback(GL_POINTS);
835 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bytesNeeded - 1, &tfData, GL_STATIC_DRAW);
836 EXPECT_GL_NO_ERROR();
837 glDrawArrays(GL_POINTS, 0, verticesToDraw);
838 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
839 glEndTransformFeedback();
840 }
841
842 // Test that buffer binding happens only on the current transform feedback object
TEST_P(TransformFeedbackTest,BufferBinding)843 TEST_P(TransformFeedbackTest, BufferBinding)
844 {
845 // http://anglebug.com/5154
846 ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
847
848 // Reset any state
849 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
850 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
851
852 // Generate a new buffer
853 GLuint scratchBuffer = 0;
854 glGenBuffers(1, &scratchBuffer);
855
856 EXPECT_GL_NO_ERROR();
857
858 // Bind TF 0 and a buffer
859 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
860 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
861
862 EXPECT_GL_NO_ERROR();
863
864 // Check that the buffer ID matches the one that was just bound
865 GLint currentBufferBinding = 0;
866 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, ¤tBufferBinding);
867 EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), mTransformFeedbackBuffer);
868
869 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, ¤tBufferBinding);
870 EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), mTransformFeedbackBuffer);
871
872 EXPECT_GL_NO_ERROR();
873
874 // Check that the buffer ID for the newly bound transform feedback is zero
875 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
876
877 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, ¤tBufferBinding);
878 EXPECT_EQ(0, currentBufferBinding);
879
880 // But the generic bind point is unaffected by glBindTransformFeedback.
881 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, ¤tBufferBinding);
882 EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), mTransformFeedbackBuffer);
883
884 EXPECT_GL_NO_ERROR();
885
886 // Bind a buffer to this TF
887 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, scratchBuffer, 0, 32);
888
889 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, ¤tBufferBinding);
890 EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), scratchBuffer);
891
892 EXPECT_GL_NO_ERROR();
893
894 // Rebind the original TF and check it's bindings
895 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
896
897 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, ¤tBufferBinding);
898 EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), mTransformFeedbackBuffer);
899
900 EXPECT_GL_NO_ERROR();
901
902 // Clean up
903 glDeleteBuffers(1, &scratchBuffer);
904 }
905
906 // Test that we can capture varyings only used in the vertex shader.
TEST_P(TransformFeedbackTest,VertexOnly)907 TEST_P(TransformFeedbackTest, VertexOnly)
908 {
909 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
910 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
911
912 constexpr char kVS[] =
913 "#version 300 es\n"
914 "in vec2 position;\n"
915 "in float attrib;\n"
916 "out float varyingAttrib;\n"
917 "void main() {\n"
918 " gl_Position = vec4(position, 0, 1);\n"
919 " varyingAttrib = attrib;\n"
920 "}";
921
922 constexpr char kFS[] =
923 "#version 300 es\n"
924 "out mediump vec4 color;\n"
925 "void main() {\n"
926 " color = vec4(0.0, 1.0, 0.0, 1.0);\n"
927 "}";
928
929 std::vector<std::string> tfVaryings;
930 tfVaryings.push_back("varyingAttrib");
931
932 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
933 ASSERT_NE(0u, mProgram);
934
935 glUseProgram(mProgram);
936
937 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
938 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
939
940 std::vector<float> attribData;
941 for (unsigned int cnt = 0; cnt < 100; ++cnt)
942 {
943 attribData.push_back(static_cast<float>(cnt));
944 }
945
946 GLint attribLocation = glGetAttribLocation(mProgram, "attrib");
947 ASSERT_NE(-1, attribLocation);
948
949 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, &attribData[0]);
950 glEnableVertexAttribArray(attribLocation);
951
952 glBeginTransformFeedback(GL_TRIANGLES);
953 drawQuad(mProgram, "position", 0.5f);
954 glEndTransformFeedback();
955 ASSERT_GL_NO_ERROR();
956
957 glUseProgram(0);
958
959 void *mappedBuffer =
960 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 6, GL_MAP_READ_BIT);
961 ASSERT_NE(nullptr, mappedBuffer);
962
963 float *mappedFloats = static_cast<float *>(mappedBuffer);
964 for (unsigned int cnt = 0; cnt < 6; ++cnt)
965 {
966 EXPECT_EQ(attribData[cnt], mappedFloats[cnt]);
967 }
968 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
969
970 EXPECT_GL_NO_ERROR();
971 }
972
973 // Test that we can link inactive structure type vayrings with xfb and capture varyings only used in
974 // the vertex shader.
TEST_P(TransformFeedbackTest,InactiveStructureVarying)975 TEST_P(TransformFeedbackTest, InactiveStructureVarying)
976 {
977 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
978 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
979
980 constexpr char kVS[] =
981 R"(#version 300 es
982 in vec2 position;
983 in float attrib;
984 flat out struct
985 {
986 int test1;
987 float test2;
988 } outStruct;
989 out float varyingAttrib;
990 void main() {
991 gl_Position = vec4(position, 0, 1);
992 varyingAttrib = attrib;
993 })";
994
995 constexpr char kFS[] =
996 R"(#version 300 es
997 out mediump vec4 color;
998 void main() {
999 color = vec4(0.0, 1.0, 0.0, 1.0);
1000 })";
1001
1002 std::vector<std::string> tfVaryings;
1003 tfVaryings.push_back("varyingAttrib");
1004
1005 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1006 ASSERT_NE(0u, mProgram);
1007
1008 glUseProgram(mProgram);
1009
1010 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1011 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1012
1013 std::vector<float> attribData;
1014 for (unsigned int cnt = 0; cnt < 100; ++cnt)
1015 {
1016 attribData.push_back(static_cast<float>(cnt));
1017 }
1018
1019 GLint attribLocation = glGetAttribLocation(mProgram, "attrib");
1020 ASSERT_NE(-1, attribLocation);
1021
1022 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, &attribData[0]);
1023 glEnableVertexAttribArray(attribLocation);
1024
1025 glBeginTransformFeedback(GL_TRIANGLES);
1026 drawQuad(mProgram, "position", 0.5f);
1027 glEndTransformFeedback();
1028 ASSERT_GL_NO_ERROR();
1029
1030 glUseProgram(0);
1031
1032 void *mappedBuffer =
1033 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 6, GL_MAP_READ_BIT);
1034 ASSERT_NE(nullptr, mappedBuffer);
1035
1036 float *mappedFloats = static_cast<float *>(mappedBuffer);
1037 for (unsigned int cnt = 0; cnt < 6; ++cnt)
1038 {
1039 EXPECT_EQ(attribData[cnt], mappedFloats[cnt]);
1040 }
1041 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1042
1043 EXPECT_GL_NO_ERROR();
1044 }
1045
1046 // Test that multiple paused transform feedbacks do not generate errors or crash
TEST_P(TransformFeedbackTest,MultiplePaused)1047 TEST_P(TransformFeedbackTest, MultiplePaused)
1048 {
1049 // Crashes on Mac Intel GL drivers. http://anglebug.com/4992
1050 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsOSX());
1051
1052 const size_t drawSize = 1024;
1053 std::vector<float> transformFeedbackData(drawSize);
1054 for (size_t i = 0; i < drawSize; i++)
1055 {
1056 transformFeedbackData[i] = static_cast<float>(i + 1);
1057 }
1058
1059 // Initialize the buffers to zero
1060 size_t bufferSize = drawSize;
1061 std::vector<float> bufferInitialData(bufferSize, 0);
1062
1063 const size_t transformFeedbackCount = 8;
1064
1065 constexpr char kVS[] = R"(#version 300 es
1066 in highp vec4 position;
1067 in float transformFeedbackInput;
1068 out float transformFeedbackOutput;
1069 void main(void)
1070 {
1071 gl_Position = position;
1072 transformFeedbackOutput = transformFeedbackInput;
1073 })";
1074
1075 constexpr char kFS[] = R"(#version 300 es
1076 out mediump vec4 color;
1077 void main(void)
1078 {
1079 color = vec4(1.0, 1.0, 1.0, 1.0);
1080 })";
1081
1082 std::vector<std::string> tfVaryings;
1083 tfVaryings.push_back("transformFeedbackOutput");
1084
1085 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1086 ASSERT_NE(0u, mProgram);
1087 glUseProgram(mProgram);
1088
1089 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1090 glDisableVertexAttribArray(positionLocation);
1091 glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
1092
1093 GLint tfInputLocation = glGetAttribLocation(mProgram, "transformFeedbackInput");
1094 glEnableVertexAttribArray(tfInputLocation);
1095 glVertexAttribPointer(tfInputLocation, 1, GL_FLOAT, false, 0, &transformFeedbackData[0]);
1096
1097 glDepthMask(GL_FALSE);
1098 glEnable(GL_DEPTH_TEST);
1099 ASSERT_GL_NO_ERROR();
1100
1101 GLuint transformFeedbacks[transformFeedbackCount];
1102 glGenTransformFeedbacks(transformFeedbackCount, transformFeedbacks);
1103
1104 GLuint buffers[transformFeedbackCount];
1105 glGenBuffers(transformFeedbackCount, buffers);
1106
1107 for (size_t i = 0; i < transformFeedbackCount; i++)
1108 {
1109 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
1110
1111 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffers[i]);
1112 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bufferSize * sizeof(GLfloat),
1113 &bufferInitialData[0], GL_DYNAMIC_DRAW);
1114 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffers[i]);
1115 ASSERT_GL_NO_ERROR();
1116
1117 glBeginTransformFeedback(GL_POINTS);
1118
1119 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(drawSize));
1120
1121 glPauseTransformFeedback();
1122
1123 EXPECT_GL_NO_ERROR();
1124 }
1125
1126 for (size_t i = 0; i < transformFeedbackCount; i++)
1127 {
1128 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
1129 glEndTransformFeedback();
1130 glDeleteTransformFeedbacks(1, &transformFeedbacks[i]);
1131
1132 EXPECT_GL_NO_ERROR();
1133 }
1134 }
1135 // Test that running multiple simultaneous queries and transform feedbacks from multiple EGL
1136 // contexts returns the correct results. Helps expose bugs in ANGLE's virtual contexts.
TEST_P(TransformFeedbackTest,MultiContext)1137 TEST_P(TransformFeedbackTest, MultiContext)
1138 {
1139 // These tests are flaky, do not lift these unless you find the root cause and the fix.
1140 ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
1141
1142 ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsOpenGL());
1143
1144 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
1145
1146 // Flaky on Win Intel Vulkan. http://anglebug.com/4497
1147 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
1148
1149 EGLint contextAttributes[] = {
1150 EGL_CONTEXT_MAJOR_VERSION_KHR,
1151 GetParam().majorVersion,
1152 EGL_CONTEXT_MINOR_VERSION_KHR,
1153 GetParam().minorVersion,
1154 EGL_NONE,
1155 };
1156
1157 // Keep a fixed seed RNG so we are deterministic.
1158 RNG rng(0);
1159 EGLWindow *window = getEGLWindow();
1160
1161 EGLDisplay display = window->getDisplay();
1162 EGLConfig config = window->getConfig();
1163 EGLSurface surface = window->getSurface();
1164
1165 const size_t passCount = 5;
1166 struct ContextInfo
1167 {
1168 EGLContext context;
1169 GLuint program;
1170 GLuint query;
1171 GLuint buffer;
1172 size_t primitiveCounts[passCount];
1173 };
1174 static constexpr uint32_t kContextCount = 32;
1175 ContextInfo contexts[kContextCount];
1176
1177 const size_t maxDrawSize = 512;
1178
1179 std::vector<float> transformFeedbackData(maxDrawSize);
1180 for (size_t i = 0; i < maxDrawSize; i++)
1181 {
1182 transformFeedbackData[i] = static_cast<float>(i + 1);
1183 }
1184
1185 // Initialize the buffers to zero
1186 size_t bufferSize = maxDrawSize * passCount;
1187 std::vector<float> bufferInitialData(bufferSize, 0);
1188
1189 constexpr char kVS[] = R"(#version 300 es
1190 in highp vec4 position;
1191 in float transformFeedbackInput;
1192 out float transformFeedbackOutput;
1193 void main(void)
1194 {
1195 gl_Position = position;
1196 transformFeedbackOutput = transformFeedbackInput;
1197 })";
1198
1199 constexpr char kFS[] = R"(#version 300 es
1200 out mediump vec4 color;
1201 void main(void)
1202 {
1203 color = vec4(1.0, 1.0, 1.0, 1.0);
1204 })";
1205
1206 for (ContextInfo &context : contexts)
1207 {
1208 context.context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
1209 ASSERT_NE(context.context, EGL_NO_CONTEXT);
1210
1211 eglMakeCurrent(display, surface, surface, context.context);
1212
1213 std::vector<std::string> tfVaryings;
1214 tfVaryings.push_back("transformFeedbackOutput");
1215
1216 context.program =
1217 CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1218 ASSERT_NE(context.program, 0u);
1219 glUseProgram(context.program);
1220
1221 GLint positionLocation = glGetAttribLocation(context.program, "position");
1222 glDisableVertexAttribArray(positionLocation);
1223 glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
1224
1225 GLint tfInputLocation = glGetAttribLocation(context.program, "transformFeedbackInput");
1226 glEnableVertexAttribArray(tfInputLocation);
1227 glVertexAttribPointer(tfInputLocation, 1, GL_FLOAT, false, 0, &transformFeedbackData[0]);
1228
1229 glDepthMask(GL_FALSE);
1230 glEnable(GL_DEPTH_TEST);
1231 glGenQueriesEXT(1, &context.query);
1232 glBeginQueryEXT(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, context.query);
1233
1234 ASSERT_GL_NO_ERROR();
1235
1236 glGenBuffers(1, &context.buffer);
1237 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, context.buffer);
1238 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bufferSize * sizeof(GLfloat),
1239 &bufferInitialData[0], GL_DYNAMIC_DRAW);
1240 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, context.buffer);
1241
1242 ASSERT_GL_NO_ERROR();
1243
1244 // For each pass, draw between 0 and maxDrawSize primitives
1245 for (size_t &primCount : context.primitiveCounts)
1246 {
1247 primCount = rng.randomIntBetween(1, maxDrawSize);
1248 }
1249
1250 glBeginTransformFeedback(GL_POINTS);
1251 }
1252
1253 for (size_t pass = 0; pass < passCount; pass++)
1254 {
1255 for (const auto &context : contexts)
1256 {
1257 eglMakeCurrent(display, surface, surface, context.context);
1258
1259 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(context.primitiveCounts[pass]));
1260 }
1261 }
1262
1263 for (const auto &context : contexts)
1264 {
1265 eglMakeCurrent(display, surface, surface, context.context);
1266
1267 glEndTransformFeedback();
1268
1269 glEndQueryEXT(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
1270
1271 GLuint result = 0;
1272 glGetQueryObjectuivEXT(context.query, GL_QUERY_RESULT_EXT, &result);
1273
1274 EXPECT_GL_NO_ERROR();
1275
1276 size_t totalPrimCount = 0;
1277 for (const auto &primCount : context.primitiveCounts)
1278 {
1279 totalPrimCount += primCount;
1280 }
1281 EXPECT_EQ(static_cast<GLuint>(totalPrimCount), result);
1282
1283 const float *bufferData = reinterpret_cast<float *>(glMapBufferRange(
1284 GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferSize * sizeof(GLfloat), GL_MAP_READ_BIT));
1285
1286 size_t curBufferIndex = 0;
1287 unsigned int failures = 0;
1288 for (const auto &primCount : context.primitiveCounts)
1289 {
1290 for (size_t prim = 0; prim < primCount; prim++)
1291 {
1292 failures += (bufferData[curBufferIndex] != (prim + 1)) ? 1 : 0;
1293 curBufferIndex++;
1294 }
1295 }
1296
1297 EXPECT_EQ(0u, failures);
1298
1299 while (curBufferIndex < bufferSize)
1300 {
1301 EXPECT_EQ(bufferData[curBufferIndex], 0.0f);
1302 curBufferIndex++;
1303 }
1304
1305 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1306 }
1307
1308 eglMakeCurrent(display, surface, surface, window->getContext());
1309
1310 for (auto &context : contexts)
1311 {
1312 eglDestroyContext(display, context.context);
1313 context.context = EGL_NO_CONTEXT;
1314 }
1315 }
1316
1317 // Test that when two vec2s are packed into the same register, we can still capture both of them.
TEST_P(TransformFeedbackTest,PackingBug)1318 TEST_P(TransformFeedbackTest, PackingBug)
1319 {
1320 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
1321 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
1322
1323 // TODO(anglebug.com/5360): Timing out on ARM-based Apple DTKs.
1324 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
1325
1326 // TODO(jmadill): With points and rasterizer discard?
1327 constexpr char kVS[] =
1328 "#version 300 es\n"
1329 "in vec2 inAttrib1;\n"
1330 "in vec2 inAttrib2;\n"
1331 "out vec2 outAttrib1;\n"
1332 "out vec2 outAttrib2;\n"
1333 "in vec2 position;\n"
1334 "void main() {"
1335 " outAttrib1 = inAttrib1;\n"
1336 " outAttrib2 = inAttrib2;\n"
1337 " gl_Position = vec4(position, 0, 1);\n"
1338 "}";
1339
1340 constexpr char kFS[] =
1341 "#version 300 es\n"
1342 "precision mediump float;\n"
1343 "out vec4 color;\n"
1344 "void main() {\n"
1345 " color = vec4(0);\n"
1346 "}";
1347
1348 std::vector<std::string> tfVaryings;
1349 tfVaryings.push_back("outAttrib1");
1350 tfVaryings.push_back("outAttrib2");
1351
1352 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1353 ASSERT_NE(0u, mProgram);
1354
1355 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1356 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector2) * 2 * 6, nullptr, GL_STREAM_DRAW);
1357
1358 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1359 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1360
1361 GLint attrib1Loc = glGetAttribLocation(mProgram, "inAttrib1");
1362 GLint attrib2Loc = glGetAttribLocation(mProgram, "inAttrib2");
1363
1364 std::vector<Vector2> attrib1Data;
1365 std::vector<Vector2> attrib2Data;
1366 int counter = 0;
1367 for (size_t i = 0; i < 6; i++)
1368 {
1369 attrib1Data.push_back(Vector2(counter + 0.0f, counter + 1.0f));
1370 attrib2Data.push_back(Vector2(counter + 2.0f, counter + 3.0f));
1371 counter += 4;
1372 }
1373
1374 glEnableVertexAttribArray(attrib1Loc);
1375 glEnableVertexAttribArray(attrib2Loc);
1376
1377 glVertexAttribPointer(attrib1Loc, 2, GL_FLOAT, GL_FALSE, 0, attrib1Data.data());
1378 glVertexAttribPointer(attrib2Loc, 2, GL_FLOAT, GL_FALSE, 0, attrib2Data.data());
1379
1380 glUseProgram(mProgram);
1381 glBeginTransformFeedback(GL_TRIANGLES);
1382 drawQuad(mProgram, "position", 0.5f);
1383 glEndTransformFeedback();
1384 glUseProgram(0);
1385 ASSERT_GL_NO_ERROR();
1386
1387 const void *mapPointer =
1388 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector2) * 2 * 6, GL_MAP_READ_BIT);
1389 ASSERT_NE(nullptr, mapPointer);
1390
1391 const Vector2 *vecPointer = static_cast<const Vector2 *>(mapPointer);
1392 for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
1393 {
1394 unsigned int stream1Index = vectorIndex * 2;
1395 unsigned int stream2Index = vectorIndex * 2 + 1;
1396 EXPECT_EQ(attrib1Data[vectorIndex], vecPointer[stream1Index]);
1397 EXPECT_EQ(attrib2Data[vectorIndex], vecPointer[stream2Index]);
1398 }
1399 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1400
1401 ASSERT_GL_NO_ERROR();
1402 }
1403
1404 // Test that transform feedback varyings that can be optimized out yet do not cause program
1405 // compilation to fail
TEST_P(TransformFeedbackTest,OptimizedVaryings)1406 TEST_P(TransformFeedbackTest, OptimizedVaryings)
1407 {
1408 constexpr char kVS[] =
1409 "#version 300 es\n"
1410 "in vec4 a_vertex;\n"
1411 "in vec3 a_normal; \n"
1412 "\n"
1413 "uniform Transform\n"
1414 "{\n"
1415 " mat4 u_modelViewMatrix;\n"
1416 " mat4 u_projectionMatrix;\n"
1417 " mat3 u_normalMatrix;\n"
1418 "};\n"
1419 "\n"
1420 "out vec3 normal;\n"
1421 "out vec4 ecPosition;\n"
1422 "\n"
1423 "void main()\n"
1424 "{\n"
1425 " normal = normalize(u_normalMatrix * a_normal);\n"
1426 " ecPosition = u_modelViewMatrix * a_vertex;\n"
1427 " gl_Position = u_projectionMatrix * ecPosition;\n"
1428 "}\n";
1429
1430 constexpr char kFS[] =
1431 "#version 300 es\n"
1432 "precision mediump float;\n"
1433 "\n"
1434 "in vec3 normal;\n"
1435 "in vec4 ecPosition;\n"
1436 "\n"
1437 "out vec4 fragColor;\n"
1438 "\n"
1439 "void main()\n"
1440 "{\n"
1441 " fragColor = vec4(normal/2.0+vec3(0.5), 1);\n"
1442 "}\n";
1443
1444 std::vector<std::string> tfVaryings;
1445 tfVaryings.push_back("normal");
1446 tfVaryings.push_back("ecPosition");
1447
1448 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1449 ASSERT_NE(0u, mProgram);
1450 }
1451
1452 // Test an edge case where two varyings are unreferenced in the frag shader.
TEST_P(TransformFeedbackTest,TwoUnreferencedInFragShader)1453 TEST_P(TransformFeedbackTest, TwoUnreferencedInFragShader)
1454 {
1455 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
1456 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
1457 // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
1458 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
1459
1460 // TODO(jmadill): With points and rasterizer discard?
1461 constexpr char kVS[] =
1462 "#version 300 es\n"
1463 "in vec3 position;\n"
1464 "out vec3 outAttrib1;\n"
1465 "out vec3 outAttrib2;\n"
1466 "void main() {"
1467 " outAttrib1 = position;\n"
1468 " outAttrib2 = position;\n"
1469 " gl_Position = vec4(position, 1);\n"
1470 "}";
1471
1472 constexpr char kFS[] =
1473 "#version 300 es\n"
1474 "precision mediump float;\n"
1475 "out vec4 color;\n"
1476 "in vec3 outAttrib1;\n"
1477 "in vec3 outAttrib2;\n"
1478 "void main() {\n"
1479 " color = vec4(0);\n"
1480 "}";
1481
1482 std::vector<std::string> tfVaryings;
1483 tfVaryings.push_back("outAttrib1");
1484 tfVaryings.push_back("outAttrib2");
1485
1486 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1487 ASSERT_NE(0u, mProgram);
1488
1489 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1490 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector3) * 2 * 6, nullptr, GL_STREAM_DRAW);
1491
1492 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1493 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1494
1495 glUseProgram(mProgram);
1496 glBeginTransformFeedback(GL_TRIANGLES);
1497 drawQuad(mProgram, "position", 0.5f);
1498 glEndTransformFeedback();
1499 glUseProgram(0);
1500 ASSERT_GL_NO_ERROR();
1501
1502 const void *mapPointer =
1503 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 2 * 6, GL_MAP_READ_BIT);
1504 ASSERT_NE(nullptr, mapPointer);
1505
1506 const auto &quadVertices = GetQuadVertices();
1507
1508 const Vector3 *vecPointer = static_cast<const Vector3 *>(mapPointer);
1509 for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
1510 {
1511 unsigned int stream1Index = vectorIndex * 2;
1512 unsigned int stream2Index = vectorIndex * 2 + 1;
1513 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
1514 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
1515 }
1516 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1517
1518 ASSERT_GL_NO_ERROR();
1519 }
1520
1521 // Test that the transform feedback write offset is reset to the buffer's offset when
1522 // glBeginTransformFeedback is called
TEST_P(TransformFeedbackTest,OffsetResetOnBeginTransformFeedback)1523 TEST_P(TransformFeedbackTest, OffsetResetOnBeginTransformFeedback)
1524 {
1525 // http://anglebug.com/5069
1526 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX() && IsAMD());
1527
1528 // http://anglebug.com/5069
1529 ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());
1530
1531 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
1532 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
1533
1534 constexpr char kVS[] =
1535 "#version 300 es\n"
1536 "in vec4 position;\n"
1537 "out vec4 outAttrib;\n"
1538 "void main() {"
1539 " outAttrib = position;\n"
1540 " gl_Position = vec4(0);\n"
1541 "}";
1542
1543 constexpr char kFS[] =
1544 "#version 300 es\n"
1545 "precision mediump float;\n"
1546 "out vec4 color;\n"
1547 "void main() {\n"
1548 " color = vec4(0);\n"
1549 "}";
1550
1551 std::vector<std::string> tfVaryings;
1552 tfVaryings.push_back("outAttrib");
1553
1554 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1555 ASSERT_NE(0u, mProgram);
1556
1557 GLint positionLocation = glGetAttribLocation(mProgram, "position");
1558
1559 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1560 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector4) * 2, nullptr, GL_STREAM_DRAW);
1561
1562 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1563 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1564
1565 glUseProgram(mProgram);
1566
1567 Vector4 drawVertex0(4, 3, 2, 1);
1568 Vector4 drawVertex1(8, 7, 6, 5);
1569 Vector4 drawVertex2(12, 11, 10, 9);
1570
1571 glEnableVertexAttribArray(positionLocation);
1572
1573 glBeginTransformFeedback(GL_POINTS);
1574
1575 // Write vertex 0 at offset 0
1576 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, false, 0, &drawVertex0);
1577 glDrawArrays(GL_POINTS, 0, 1);
1578
1579 // Append vertex 1
1580 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, false, 0, &drawVertex1);
1581 glDrawArrays(GL_POINTS, 0, 1);
1582
1583 glEndTransformFeedback();
1584 glBeginTransformFeedback(GL_POINTS);
1585
1586 // Write vertex 2 at offset 0
1587 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, false, 0, &drawVertex2);
1588 glDrawArrays(GL_POINTS, 0, 1);
1589
1590 glEndTransformFeedback();
1591
1592 const void *mapPointer =
1593 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector4) * 2, GL_MAP_READ_BIT);
1594 ASSERT_NE(nullptr, mapPointer);
1595
1596 const Vector4 *vecPointer = static_cast<const Vector4 *>(mapPointer);
1597 ASSERT_EQ(drawVertex2, vecPointer[0]);
1598 ASSERT_EQ(drawVertex1, vecPointer[1]);
1599
1600 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1601
1602 ASSERT_GL_NO_ERROR();
1603 }
1604
1605 // Test that the captured buffer can be copied to other buffers.
TEST_P(TransformFeedbackTest,CaptureAndCopy)1606 TEST_P(TransformFeedbackTest, CaptureAndCopy)
1607 {
1608
1609 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1610 glClear(GL_COLOR_BUFFER_BIT);
1611
1612 // Set the program's transform feedback varyings (just gl_Position)
1613 std::vector<std::string> tfVaryings;
1614 tfVaryings.push_back("gl_Position");
1615 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
1616
1617 glUseProgram(mProgram);
1618
1619 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
1620
1621 glEnable(GL_RASTERIZER_DISCARD);
1622
1623 const GLfloat vertices[] = {
1624 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
1625
1626 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
1627 };
1628
1629 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
1630 glEnableVertexAttribArray(positionLocation);
1631
1632 // Bind the buffer for transform feedback output and start transform feedback
1633 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1634 glBeginTransformFeedback(GL_POINTS);
1635
1636 glDrawArrays(GL_POINTS, 0, 6);
1637
1638 glDisableVertexAttribArray(positionLocation);
1639 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
1640 glEndTransformFeedback();
1641 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
1642 glDisable(GL_RASTERIZER_DISCARD);
1643
1644 // Allocate a buffer with one byte
1645 uint8_t singleByte[] = {0xaa};
1646
1647 // Create a new buffer and copy the first byte of captured data to it
1648 GLBuffer copyBuffer;
1649 glBindBuffer(GL_COPY_WRITE_BUFFER, copyBuffer);
1650 glBufferData(GL_COPY_WRITE_BUFFER, 1, singleByte, GL_DYNAMIC_DRAW);
1651 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1652 glCopyBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 1);
1653
1654 EXPECT_GL_NO_ERROR();
1655 }
1656
1657 class TransformFeedbackLifetimeTest : public TransformFeedbackTest
1658 {
1659 protected:
TransformFeedbackLifetimeTest()1660 TransformFeedbackLifetimeTest() : mVertexArray(0) {}
1661
testSetUp()1662 void testSetUp() override
1663 {
1664 glGenVertexArrays(1, &mVertexArray);
1665 glBindVertexArray(mVertexArray);
1666
1667 std::vector<std::string> tfVaryings;
1668 tfVaryings.push_back("gl_Position");
1669 compileDefaultProgram(tfVaryings, GL_SEPARATE_ATTRIBS);
1670
1671 glGenBuffers(1, &mTransformFeedbackBuffer);
1672 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1673 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, nullptr,
1674 GL_DYNAMIC_DRAW);
1675 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1676
1677 glGenTransformFeedbacks(1, &mTransformFeedback);
1678
1679 ASSERT_GL_NO_ERROR();
1680 }
1681
testTearDown()1682 void testTearDown() override
1683 {
1684 glDeleteVertexArrays(1, &mVertexArray);
1685 TransformFeedbackTest::testTearDown();
1686 }
1687
1688 GLuint mVertexArray;
1689 };
1690
1691 // Tests a bug with state syncing and deleted transform feedback buffers.
TEST_P(TransformFeedbackLifetimeTest,DeletedBuffer)1692 TEST_P(TransformFeedbackLifetimeTest, DeletedBuffer)
1693 {
1694 // First stream vertex data to mTransformFeedbackBuffer.
1695 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1696 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1697
1698 glUseProgram(mProgram);
1699
1700 glBeginTransformFeedback(GL_TRIANGLES);
1701 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
1702 glEndTransformFeedback();
1703
1704 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1705
1706 // TODO(jmadill): Remove this when http://anglebug.com/1351 is fixed.
1707 glBindVertexArray(0);
1708 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
1709 glBindVertexArray(1);
1710
1711 // Next, draw vertices with mTransformFeedbackBuffer. This will link to mVertexArray.
1712 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
1713 GLint loc = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
1714 ASSERT_NE(-1, loc);
1715 glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
1716 glEnableVertexAttribArray(loc);
1717 glBindBuffer(GL_ARRAY_BUFFER, 0);
1718 glDrawArrays(GL_TRIANGLES, 0, 3);
1719
1720 // Delete resources, making a stranded pointer to mVertexArray in mTransformFeedbackBuffer.
1721 glDeleteBuffers(1, &mTransformFeedbackBuffer);
1722 mTransformFeedbackBuffer = 0;
1723 glDeleteVertexArrays(1, &mVertexArray);
1724 mVertexArray = 0;
1725
1726 // Then draw again with transform feedback, dereferencing the stranded pointer.
1727 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1728 glBeginTransformFeedback(GL_TRIANGLES);
1729 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
1730 glEndTransformFeedback();
1731 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1732
1733 ASSERT_GL_NO_ERROR();
1734 }
1735
1736 class TransformFeedbackTestES31 : public TransformFeedbackTestBase
1737 {};
1738
1739 // Test that program link fails in case that transform feedback names including same array element.
TEST_P(TransformFeedbackTestES31,SameArrayElementVaryings)1740 TEST_P(TransformFeedbackTestES31, SameArrayElementVaryings)
1741 {
1742 constexpr char kVS[] =
1743 "#version 310 es\n"
1744 "in vec3 position;\n"
1745 "out vec3 outAttribs[3];\n"
1746 "void main() {"
1747 " outAttribs[0] = position;\n"
1748 " outAttribs[1] = vec3(0, 0, 0);\n"
1749 " outAttribs[2] = position;\n"
1750 " gl_Position = vec4(position, 1);\n"
1751 "}";
1752
1753 constexpr char kFS[] =
1754 "#version 310 es\n"
1755 "precision mediump float;\n"
1756 "out vec4 color;\n"
1757 "in vec3 outAttribs[3];\n"
1758 "void main() {\n"
1759 " color = vec4(0);\n"
1760 "}";
1761
1762 std::vector<std::string> tfVaryings;
1763 tfVaryings.push_back("outAttribs");
1764 tfVaryings.push_back("outAttribs[1]");
1765
1766 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1767 ASSERT_EQ(0u, mProgram);
1768 }
1769
1770 // Test that program link fails in case to capture array element on a non-array varying.
TEST_P(TransformFeedbackTestES31,ElementCaptureOnNonArrayVarying)1771 TEST_P(TransformFeedbackTestES31, ElementCaptureOnNonArrayVarying)
1772 {
1773 constexpr char kVS[] =
1774 "#version 310 es\n"
1775 "in vec3 position;\n"
1776 "out vec3 outAttrib;\n"
1777 "void main() {"
1778 " outAttrib = position;\n"
1779 " gl_Position = vec4(position, 1);\n"
1780 "}";
1781
1782 constexpr char kFS[] =
1783 "#version 310 es\n"
1784 "precision mediump float;\n"
1785 "out vec4 color;\n"
1786 "in vec3 outAttrib;\n"
1787 "void main() {\n"
1788 " color = vec4(0);\n"
1789 "}";
1790
1791 std::vector<std::string> tfVaryings;
1792 tfVaryings.push_back("outAttrib[1]");
1793
1794 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1795 ASSERT_EQ(0u, mProgram);
1796 }
1797
1798 // Test that program link fails in case to capure an outbound array element.
TEST_P(TransformFeedbackTestES31,CaptureOutboundElement)1799 TEST_P(TransformFeedbackTestES31, CaptureOutboundElement)
1800 {
1801 constexpr char kVS[] =
1802 "#version 310 es\n"
1803 "in vec3 position;\n"
1804 "out vec3 outAttribs[3];\n"
1805 "void main() {"
1806 " outAttribs[0] = position;\n"
1807 " outAttribs[1] = vec3(0, 0, 0);\n"
1808 " outAttribs[2] = position;\n"
1809 " gl_Position = vec4(position, 1);\n"
1810 "}";
1811
1812 constexpr char kFS[] =
1813 "#version 310 es\n"
1814 "precision mediump float;\n"
1815 "out vec4 color;\n"
1816 "in vec3 outAttribs[3];\n"
1817 "void main() {\n"
1818 " color = vec4(0);\n"
1819 "}";
1820
1821 std::vector<std::string> tfVaryings;
1822 tfVaryings.push_back("outAttribs[3]");
1823
1824 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1825 ASSERT_EQ(0u, mProgram);
1826 }
1827
1828 // Test transform feedback names can be specified using array element.
TEST_P(TransformFeedbackTestES31,DifferentArrayElementVaryings)1829 TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
1830 {
1831 // Remove this when http://anglebug.com/4140 is fixed.
1832 ANGLE_SKIP_TEST_IF(IsVulkan());
1833
1834 constexpr char kVS[] =
1835 "#version 310 es\n"
1836 "in vec3 position;\n"
1837 "out vec3 outAttribs[3];\n"
1838 "void main() {"
1839 " outAttribs[0] = position;\n"
1840 " outAttribs[1] = vec3(0, 0, 0);\n"
1841 " outAttribs[2] = position;\n"
1842 " gl_Position = vec4(position, 1);\n"
1843 "}";
1844
1845 constexpr char kFS[] =
1846 "#version 310 es\n"
1847 "precision mediump float;\n"
1848 "out vec4 color;\n"
1849 "in vec3 outAttribs[3];\n"
1850 "void main() {\n"
1851 " color = vec4(0);\n"
1852 "}";
1853
1854 std::vector<std::string> tfVaryings;
1855 tfVaryings.push_back("outAttribs[0]");
1856 tfVaryings.push_back("outAttribs[2]");
1857
1858 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1859 ASSERT_NE(0u, mProgram);
1860
1861 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1862 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector3) * 2 * 6, nullptr, GL_STREAM_DRAW);
1863
1864 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1865 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1866
1867 glUseProgram(mProgram);
1868 glBeginTransformFeedback(GL_TRIANGLES);
1869 drawQuad(mProgram, "position", 0.5f);
1870 glEndTransformFeedback();
1871 glUseProgram(0);
1872 ASSERT_GL_NO_ERROR();
1873
1874 const GLvoid *mapPointer =
1875 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 2 * 6, GL_MAP_READ_BIT);
1876 ASSERT_NE(nullptr, mapPointer);
1877
1878 const auto &quadVertices = GetQuadVertices();
1879
1880 const Vector3 *vecPointer = static_cast<const Vector3 *>(mapPointer);
1881 for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
1882 {
1883 unsigned int stream1Index = vectorIndex * 2;
1884 unsigned int stream2Index = vectorIndex * 2 + 1;
1885 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
1886 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
1887 }
1888 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1889
1890 ASSERT_GL_NO_ERROR();
1891 }
1892
1893 // Test transform feedback varying for base-level members of struct.
TEST_P(TransformFeedbackTestES31,StructMemberVaryings)1894 TEST_P(TransformFeedbackTestES31, StructMemberVaryings)
1895 {
1896 // Remove this when http://anglebug.com/4140 is fixed.
1897 ANGLE_SKIP_TEST_IF(IsVulkan());
1898
1899 constexpr char kVS[] = R"(#version 310 es
1900 in vec3 position;
1901 struct S {
1902 vec3 field0;
1903 vec3 field1;
1904 vec3 field2;
1905 };
1906 out S s;
1907
1908 void main() {
1909 s.field0 = position;
1910 s.field1 = vec3(0, 0, 0);
1911 s.field2 = position;
1912 gl_Position = vec4(position, 1);
1913 })";
1914
1915 constexpr char kFS[] = R"(#version 310 es
1916 precision mediump float;
1917 struct S {
1918 vec3 field0;
1919 vec3 field1;
1920 vec3 field2;
1921 };
1922 out vec4 color;
1923 in S s;
1924
1925 void main() {
1926 color = vec4(s.field1, 1);
1927 })";
1928
1929 std::vector<std::string> tfVaryings;
1930 tfVaryings.push_back("s.field0");
1931 tfVaryings.push_back("s.field2");
1932
1933 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1934 ASSERT_NE(0u, mProgram);
1935
1936 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
1937 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector3) * 2 * 6, nullptr, GL_STREAM_DRAW);
1938
1939 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
1940 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1941
1942 glUseProgram(mProgram);
1943 glBeginTransformFeedback(GL_TRIANGLES);
1944 drawQuad(mProgram, "position", 0.5f);
1945 glEndTransformFeedback();
1946 glUseProgram(0);
1947 ASSERT_GL_NO_ERROR();
1948
1949 const GLvoid *mapPointer =
1950 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 2 * 6, GL_MAP_READ_BIT);
1951 ASSERT_NE(nullptr, mapPointer);
1952
1953 const auto &quadVertices = GetQuadVertices();
1954
1955 const Vector3 *vecPointer = static_cast<const Vector3 *>(mapPointer);
1956 for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
1957 {
1958 unsigned int stream1Index = vectorIndex * 2;
1959 unsigned int stream2Index = vectorIndex * 2 + 1;
1960 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream1Index]);
1961 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[stream2Index]);
1962 }
1963 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1964
1965 ASSERT_GL_NO_ERROR();
1966 }
1967
1968 // Test transform feedback varying for struct is not allowed.
TEST_P(TransformFeedbackTestES31,InvalidStructVaryings)1969 TEST_P(TransformFeedbackTestES31, InvalidStructVaryings)
1970 {
1971 constexpr char kVS[] = R"(#version 310 es
1972 in vec3 position;
1973 struct S {
1974 vec3 field0;
1975 vec3 field1;
1976 };
1977 out S s;
1978
1979 void main() {
1980 s.field0 = position;
1981 s.field1 = vec3(0, 0, 0);
1982 gl_Position = vec4(position, 1);
1983 })";
1984
1985 constexpr char kFS[] = R"(#version 310 es
1986 precision mediump float;
1987 struct S {
1988 vec3 field0;
1989 vec3 field1;
1990 };
1991 out vec4 color;
1992 in S s;
1993
1994 void main() {
1995 color = vec4(s.field1, 1);
1996 })";
1997
1998 std::vector<std::string> tfVaryings;
1999 tfVaryings.push_back("s");
2000
2001 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
2002 ASSERT_EQ(0u, mProgram);
2003 }
2004
2005 // Test transform feedback can capture the whole array
TEST_P(TransformFeedbackTestES31,CaptureArray)2006 TEST_P(TransformFeedbackTestES31, CaptureArray)
2007 {
2008 constexpr char kVS[] = R"(#version 310 es
2009 in vec4 a_position;
2010 in float a_varA;
2011 in float a_varB1;
2012 in float a_varB2;
2013 out float v_varA[1];
2014 out float v_varB[2];
2015 void main()
2016 {
2017 gl_Position = a_position;
2018 gl_PointSize = 1.0;
2019 v_varA[0] = a_varA;
2020 v_varB[0] = a_varB1;
2021 v_varB[1] = a_varB2;
2022 })";
2023
2024 constexpr char kFS[] = R"(#version 310 es
2025 precision mediump float;
2026 in float v_varA[1];
2027 in float v_varB[2];
2028 out vec4 fragColor;
2029 void main()
2030 {
2031 vec4 res = vec4(0.0);
2032 res += vec4(v_varA[0]);
2033 res += vec4(v_varB[0]);
2034 res += vec4(v_varB[1]);
2035 fragColor = res;
2036 })";
2037
2038 std::vector<std::string> tfVaryings;
2039 tfVaryings.push_back("v_varA");
2040 tfVaryings.push_back("v_varB");
2041
2042 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
2043 ASSERT_NE(0u, mProgram);
2044
2045 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
2046 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 3 * 6, nullptr, GL_STREAM_DRAW);
2047
2048 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2049 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2050
2051 GLint varA = glGetAttribLocation(mProgram, "a_varA");
2052 ASSERT_NE(-1, varA);
2053 GLint varB1 = glGetAttribLocation(mProgram, "a_varB1");
2054 ASSERT_NE(-1, varB1);
2055 GLint varB2 = glGetAttribLocation(mProgram, "a_varB2");
2056 ASSERT_NE(-1, varB2);
2057
2058 std::array<float, 6> data1 = {24.0f, 25.0f, 30.0f, 33.0f, 37.5f, 44.0f};
2059 std::array<float, 6> data2 = {48.0f, 5.0f, 55.0f, 3.1415f, 87.0f, 42.0f};
2060 std::array<float, 6> data3 = {128.0f, 1.0f, 0.0f, -1.0f, 16.0f, 1024.0f};
2061
2062 glVertexAttribPointer(varA, 1, GL_FLOAT, GL_FALSE, 0, data1.data());
2063 glEnableVertexAttribArray(varA);
2064 glVertexAttribPointer(varB1, 1, GL_FLOAT, GL_FALSE, 0, data2.data());
2065 glEnableVertexAttribArray(varB1);
2066 glVertexAttribPointer(varB2, 1, GL_FLOAT, GL_FALSE, 0, data3.data());
2067 glEnableVertexAttribArray(varB2);
2068
2069 glUseProgram(mProgram);
2070 glBeginTransformFeedback(GL_TRIANGLES);
2071 drawQuad(mProgram, "a_position", 0.5f);
2072 glEndTransformFeedback();
2073 glUseProgram(0);
2074 ASSERT_GL_NO_ERROR();
2075
2076 void *mappedBuffer =
2077 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 3 * 6, GL_MAP_READ_BIT);
2078 ASSERT_NE(nullptr, mappedBuffer);
2079
2080 float *mappedFloats = static_cast<float *>(mappedBuffer);
2081 for (int i = 0; i < 6; i++)
2082 {
2083 std::array<float, 3> mappedData = {mappedFloats[i * 3], mappedFloats[i * 3 + 1],
2084 mappedFloats[i * 3 + 2]};
2085 std::array<float, 3> data = {data1[i], data2[i], data3[i]};
2086 EXPECT_EQ(data, mappedData) << "iteration #" << i;
2087 }
2088
2089 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2090
2091 ASSERT_GL_NO_ERROR();
2092 }
2093
2094 // Test that nonexistent transform feedback varyings don't assert when linking.
TEST_P(TransformFeedbackTest,NonExistentTransformFeedbackVarying)2095 TEST_P(TransformFeedbackTest, NonExistentTransformFeedbackVarying)
2096 {
2097 std::vector<std::string> tfVaryings;
2098 tfVaryings.push_back("bogus");
2099
2100 mProgram = CompileProgramWithTransformFeedback(
2101 essl3_shaders::vs::Simple(), essl3_shaders::fs::Red(), tfVaryings, GL_INTERLEAVED_ATTRIBS);
2102 ASSERT_EQ(0u, mProgram);
2103 }
2104
2105 // Test that nonexistent transform feedback varyings don't assert when linking. In this test the
2106 // nonexistent varying is prefixed with "gl_".
TEST_P(TransformFeedbackTest,NonExistentTransformFeedbackVaryingWithGLPrefix)2107 TEST_P(TransformFeedbackTest, NonExistentTransformFeedbackVaryingWithGLPrefix)
2108 {
2109 // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
2110 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
2111
2112 std::vector<std::string> tfVaryings;
2113 tfVaryings.push_back("gl_Bogus");
2114
2115 mProgram = CompileProgramWithTransformFeedback(
2116 essl3_shaders::vs::Simple(), essl3_shaders::fs::Red(), tfVaryings, GL_INTERLEAVED_ATTRIBS);
2117 ASSERT_EQ(0u, mProgram);
2118 }
2119
2120 // Test transform feedback names can be reserved names in GLSL, as long as they're not reserved in
2121 // GLSL ES.
TEST_P(TransformFeedbackTest,VaryingReservedOpenGLName)2122 TEST_P(TransformFeedbackTest, VaryingReservedOpenGLName)
2123 {
2124 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2125 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2126
2127 constexpr char kVS[] =
2128 "#version 300 es\n"
2129 "in vec3 position;\n"
2130 "out vec3 buffer;\n"
2131 "void main() {\n"
2132 " buffer = position;\n"
2133 " gl_Position = vec4(position, 1);\n"
2134 "}";
2135
2136 constexpr char kFS[] =
2137 "#version 300 es\n"
2138 "precision highp float;\n"
2139 "out vec4 color;\n"
2140 "in vec3 buffer;\n"
2141 "void main() {\n"
2142 " color = vec4(0);\n"
2143 "}";
2144
2145 std::vector<std::string> tfVaryings;
2146 tfVaryings.push_back("buffer");
2147
2148 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
2149 ASSERT_NE(0u, mProgram);
2150
2151 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
2152 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector3) * 6, nullptr, GL_STREAM_DRAW);
2153
2154 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2155 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2156
2157 glUseProgram(mProgram);
2158 glBeginTransformFeedback(GL_TRIANGLES);
2159 drawQuad(mProgram, "position", 0.5f);
2160 glEndTransformFeedback();
2161 glUseProgram(0);
2162 ASSERT_GL_NO_ERROR();
2163
2164 const GLvoid *mapPointer =
2165 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector3) * 6, GL_MAP_READ_BIT);
2166 ASSERT_NE(nullptr, mapPointer);
2167
2168 const auto &quadVertices = GetQuadVertices();
2169
2170 const Vector3 *vecPointer = static_cast<const Vector3 *>(mapPointer);
2171 for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
2172 {
2173 EXPECT_EQ(quadVertices[vectorIndex], vecPointer[vectorIndex]);
2174 }
2175 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2176
2177 ASSERT_GL_NO_ERROR();
2178 }
2179
2180 // Test that calling BeginTransformFeedback when no program is currentwill generate an
2181 // INVALID_OPERATION error.
TEST_P(TransformFeedbackTest,NoCurrentProgram)2182 TEST_P(TransformFeedbackTest, NoCurrentProgram)
2183 {
2184 glUseProgram(0);
2185 glBeginTransformFeedback(GL_TRIANGLES);
2186
2187 // GLES 3.0.5 section 2.15.2: "The error INVALID_OPERATION is also generated by
2188 // BeginTransformFeedback if no binding points would be used, either because no program object
2189 // is active or because the active program object has specified no output variables to record."
2190 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2191 }
2192
2193 // Test that calling BeginTransformFeedback when no transform feedback varyings are in use will
2194 // generate an INVALID_OPERATION error.
TEST_P(TransformFeedbackTest,NoTransformFeedbackVaryingsInUse)2195 TEST_P(TransformFeedbackTest, NoTransformFeedbackVaryingsInUse)
2196 {
2197 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
2198
2199 glUseProgram(program);
2200 glBeginTransformFeedback(GL_TRIANGLES);
2201
2202 // GLES 3.0.5 section 2.15.2: "The error INVALID_OPERATION is also generated by
2203 // BeginTransformFeedback if no binding points would be used, either because no program object
2204 // is active or because the active program object has specified no output variables to record."
2205
2206 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2207 }
2208
2209 // Test that you can pause transform feedback without drawing first.
TEST_P(TransformFeedbackTest,SwitchProgramBeforeDraw)2210 TEST_P(TransformFeedbackTest, SwitchProgramBeforeDraw)
2211 {
2212 // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
2213 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
2214
2215 std::vector<std::string> tfVaryings;
2216 tfVaryings.push_back("gl_Position");
2217 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2218 ANGLE_GL_PROGRAM(nonTFProgram, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
2219
2220 // Set up transform feedback, but pause it.
2221 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2222 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2223 glUseProgram(mProgram);
2224 glBeginTransformFeedback(GL_TRIANGLES);
2225 glPauseTransformFeedback();
2226
2227 // Switch programs and draw while transform feedback is paused.
2228 glUseProgram(nonTFProgram);
2229 GLint positionLocation = glGetAttribLocation(nonTFProgram, essl1_shaders::PositionAttrib());
2230 glDisableVertexAttribArray(positionLocation);
2231 glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
2232 glDrawArrays(GL_TRIANGLES, 0, 3);
2233
2234 glEndTransformFeedback();
2235
2236 ASSERT_GL_NO_ERROR();
2237 }
2238
2239 // Test that ending transform feedback with a different program bound does not cause internal
2240 // errors.
TEST_P(TransformFeedbackTest,EndWithDifferentProgram)2241 TEST_P(TransformFeedbackTest, EndWithDifferentProgram)
2242 {
2243 // AMD drivers fail because they perform transform feedback when it should be paused.
2244 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
2245
2246 // https://crbug.com/1207380 Pixel 2 is crashing during ES3_Vulkan_AsyncQueue testing
2247 ANGLE_SKIP_TEST_IF(IsVulkan() && IsPixel2());
2248
2249 std::vector<std::string> tfVaryings;
2250 tfVaryings.push_back("gl_Position");
2251 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2252 ANGLE_GL_PROGRAM(nonTFProgram, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
2253
2254 // Set up transform feedback, but pause it.
2255 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2256 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2257 // Make sure the buffer has zero'd data
2258 std::vector<float> data(mTransformFeedbackBufferSize / sizeof(float), 0.0f);
2259 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
2260 GL_STATIC_DRAW);
2261 glUseProgram(mProgram);
2262 glBeginTransformFeedback(GL_TRIANGLES);
2263 glPauseTransformFeedback();
2264 // Transform feedback should not happen
2265 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
2266
2267 // Draw using a different program.
2268 glUseProgram(nonTFProgram);
2269 GLint positionLocation = glGetAttribLocation(nonTFProgram, essl1_shaders::PositionAttrib());
2270 glDisableVertexAttribArray(positionLocation);
2271 glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
2272 glDrawArrays(GL_TRIANGLES, 0, 3);
2273
2274 // End transform feedback without unpausing and with a different program bound. This triggers
2275 // the bug.
2276 glEndTransformFeedback();
2277
2278 glUseProgram(mProgram);
2279 glBeginTransformFeedback(GL_TRIANGLES);
2280 // On a buggy driver without the workaround this will cause a GL error because the driver
2281 // thinks transform feedback is still paused, but rendering will still write to the transform
2282 // feedback buffers.
2283 glPauseTransformFeedback();
2284 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
2285 glEndTransformFeedback();
2286
2287 // Make sure that transform feedback did not happen. We always paused transform feedback before
2288 // rendering, but a buggy driver will fail to pause.
2289 const void *mapPointer =
2290 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector4) * 4, GL_MAP_READ_BIT);
2291 ASSERT_NE(nullptr, mapPointer);
2292 const Vector4 *vecPointer = static_cast<const Vector4 *>(mapPointer);
2293 ASSERT_EQ(vecPointer[0], Vector4(0, 0, 0, 0));
2294 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2295 ASSERT_GL_NO_ERROR();
2296 }
2297
2298 // Test that switching contexts with paused transform feedback does not cause internal errors.
TEST_P(TransformFeedbackTest,EndWithDifferentProgramContextSwitch)2299 TEST_P(TransformFeedbackTest, EndWithDifferentProgramContextSwitch)
2300 {
2301 // AMD drivers fail because they perform transform feedback when it should be paused.
2302 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
2303
2304 std::vector<std::string> tfVaryings;
2305 tfVaryings.push_back("gl_Position");
2306 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2307
2308 EGLWindow *window = getEGLWindow();
2309 EGLDisplay display = window->getDisplay();
2310 EGLConfig config = window->getConfig();
2311 EGLSurface surface = window->getSurface();
2312 EGLint contextAttributes[] = {
2313 EGL_CONTEXT_MAJOR_VERSION_KHR,
2314 GetParam().majorVersion,
2315 EGL_CONTEXT_MINOR_VERSION_KHR,
2316 GetParam().minorVersion,
2317 EGL_NONE,
2318 };
2319 auto context1 = eglGetCurrentContext();
2320 auto context2 = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
2321 ASSERT_NE(context2, EGL_NO_CONTEXT);
2322 // Compile a program on the second context.
2323 eglMakeCurrent(display, surface, surface, context2);
2324 ANGLE_GL_PROGRAM(nonTFProgram, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
2325 eglMakeCurrent(display, surface, surface, context1);
2326
2327 // Set up transform feedback, but pause it.
2328 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2329 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2330 // Make sure the buffer has zero'd data
2331 std::vector<float> data(mTransformFeedbackBufferSize / sizeof(float), 0.0f);
2332 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
2333 GL_STATIC_DRAW);
2334 glUseProgram(mProgram);
2335 glBeginTransformFeedback(GL_TRIANGLES);
2336 glPauseTransformFeedback();
2337 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
2338 // Leave transform feedback active but paused while we switch to a second context and render
2339 // something.
2340 eglMakeCurrent(display, surface, surface, context2);
2341 glUseProgram(nonTFProgram);
2342 GLint positionLocation = glGetAttribLocation(nonTFProgram, essl1_shaders::PositionAttrib());
2343 glDisableVertexAttribArray(positionLocation);
2344 glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
2345 glDrawArrays(GL_TRIANGLES, 0, 3);
2346 // Switch back to the first context and end transform feedback. On a buggy driver, this will
2347 // cause the transform feedback object to enter an invalid "inactive, but paused" state unless
2348 // the workaround is applied.
2349 eglMakeCurrent(display, surface, surface, context1);
2350 glEndTransformFeedback();
2351 glBeginTransformFeedback(GL_TRIANGLES);
2352 // On a buggy driver without the workaround this will cause a GL error because the driver
2353 // thinks transform feedback is still paused, but rendering will still write to the transform
2354 // feedback buffers.
2355 glPauseTransformFeedback();
2356 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
2357 glEndTransformFeedback();
2358
2359 // Make sure that transform feedback did not happen. We always paused transform feedback before
2360 // rendering, but a buggy driver will fail to pause.
2361 const void *mapPointer =
2362 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector4) * 4, GL_MAP_READ_BIT);
2363 ASSERT_NE(nullptr, mapPointer);
2364 const Vector4 *vecPointer = static_cast<const Vector4 *>(mapPointer);
2365 ASSERT_EQ(vecPointer[0], Vector4(0, 0, 0, 0));
2366 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2367 eglDestroyContext(display, context2);
2368 ASSERT_GL_NO_ERROR();
2369 }
2370
2371 // Test an out of memory event.
TEST_P(TransformFeedbackTest,BufferOutOfMemory)2372 TEST_P(TransformFeedbackTest, BufferOutOfMemory)
2373 {
2374 // The GL back-end throws an internal error that we can't deal with in this test.
2375 ANGLE_SKIP_TEST_IF(IsOpenGL());
2376
2377 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2378 glClear(GL_COLOR_BUFFER_BIT);
2379
2380 // Set the program's transform feedback varyings (just gl_Position)
2381 std::vector<std::string> tfVaryings;
2382 tfVaryings.push_back("gl_Position");
2383 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2384
2385 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
2386 const GLfloat vertices[] = {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 1.0f, -0.5f, 0.0f,
2387 0.5f, 1.0f, -1.0f, 0.0f, -0.5f, 0.0f, 1.0f};
2388
2389 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
2390 glEnableVertexAttribArray(positionLocation);
2391
2392 // Draw normally.
2393 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2394 glUseProgram(mProgram);
2395 glBeginTransformFeedback(GL_POINTS);
2396 glDrawArrays(GL_POINTS, 0, 5);
2397 glEndTransformFeedback();
2398 ASSERT_GL_NO_ERROR();
2399
2400 // Attempt to generate OOM and begin XFB.
2401 constexpr GLsizeiptr kLargeSize = std::numeric_limits<GLsizeiptr>::max();
2402 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, kLargeSize, nullptr, GL_STATIC_DRAW);
2403
2404 // It's not spec guaranteed to return OOM here.
2405 GLenum err = glGetError();
2406 EXPECT_TRUE(err == GL_NO_ERROR || err == GL_OUT_OF_MEMORY);
2407
2408 glBeginTransformFeedback(GL_POINTS);
2409 glDrawArrays(GL_POINTS, 0, 5);
2410 glEndTransformFeedback();
2411 }
2412
setupOverrunTest(const std::vector<GLfloat> & vertices)2413 void TransformFeedbackTest::setupOverrunTest(const std::vector<GLfloat> &vertices)
2414 {
2415 std::vector<uint8_t> zeroData(mTransformFeedbackBufferSize, 0);
2416
2417 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
2418 glBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBufferSize, zeroData.data());
2419
2420 // Draw a simple points XFB.
2421 std::vector<std::string> tfVaryings;
2422 tfVaryings.push_back("gl_Position");
2423 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2424 glUseProgram(mProgram);
2425
2426 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
2427
2428 // First pass: draw 6 points to the XFB buffer
2429 glEnable(GL_RASTERIZER_DISCARD);
2430
2431 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, vertices.data());
2432 glEnableVertexAttribArray(positionLocation);
2433
2434 // Bind the buffer for transform feedback output and start transform feedback
2435 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2436 glBeginTransformFeedback(GL_POINTS);
2437 glDrawArrays(GL_POINTS, 0, 6);
2438 }
2439
VerifyVertexFloats(const GLfloat * mapPtrFloat,const std::vector<GLfloat> & vertices,size_t copies,size_t numFloats)2440 void VerifyVertexFloats(const GLfloat *mapPtrFloat,
2441 const std::vector<GLfloat> &vertices,
2442 size_t copies,
2443 size_t numFloats)
2444 {
2445 for (size_t floatIndex = 0; floatIndex < vertices.size() * copies; ++floatIndex)
2446 {
2447 size_t vertIndex = floatIndex % vertices.size();
2448 ASSERT_EQ(mapPtrFloat[floatIndex], vertices[vertIndex]) << "at float index " << floatIndex;
2449 }
2450
2451 // The rest should be zero.
2452 for (size_t floatIndex = vertices.size() * copies; floatIndex < numFloats; ++floatIndex)
2453 {
2454 ASSERT_EQ(mapPtrFloat[floatIndex], 0) << "at float index " << floatIndex;
2455 }
2456 }
2457
2458 // Tests that stopping XFB works as expected.
TEST_P(TransformFeedbackTest,Overrun)2459 TEST_P(TransformFeedbackTest, Overrun)
2460 {
2461
2462 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2463 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2464
2465 const std::vector<GLfloat> vertices = {
2466 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
2467 -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
2468 };
2469
2470 setupOverrunTest(vertices);
2471
2472 glEndTransformFeedback();
2473
2474 // Draw a second time without XFB.
2475 glDrawArrays(GL_POINTS, 0, 6);
2476
2477 ASSERT_GL_NO_ERROR();
2478
2479 // Verify only the first data was output.
2480 const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
2481 mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
2482 const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
2483
2484 size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
2485 VerifyVertexFloats(mapPtrFloat, vertices, 1, numFloats);
2486 }
2487
2488 // Similar to the overrun test but with Pause instead of End.
TEST_P(TransformFeedbackTest,OverrunWithPause)2489 TEST_P(TransformFeedbackTest, OverrunWithPause)
2490 {
2491
2492 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2493 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2494
2495 // Fails on Mac Intel GL drivers. http://anglebug.com/4992
2496 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsOSX());
2497
2498 const std::vector<GLfloat> vertices = {
2499 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
2500 -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
2501 };
2502
2503 setupOverrunTest(vertices);
2504
2505 glPauseTransformFeedback();
2506
2507 // Draw a second time without XFB.
2508 glDrawArrays(GL_POINTS, 0, 6);
2509
2510 glEndTransformFeedback();
2511
2512 ASSERT_GL_NO_ERROR();
2513
2514 // Verify only the first data was output.
2515 const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
2516 mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
2517 const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
2518
2519 size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
2520 VerifyVertexFloats(mapPtrFloat, vertices, 1, numFloats);
2521 }
2522
2523 // Similar to the overrun test but with Pause instead of End.
TEST_P(TransformFeedbackTest,OverrunWithPauseAndResume)2524 TEST_P(TransformFeedbackTest, OverrunWithPauseAndResume)
2525 {
2526
2527 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2528 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2529
2530 // Fails on Adreno Pixel 2 GL drivers. Not a supported configuration.
2531 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAdreno() && IsAndroid());
2532
2533 // Fails on Windows Intel GL drivers. http://anglebug.com/4697
2534 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
2535
2536 const std::vector<GLfloat> vertices = {
2537 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
2538 -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
2539 };
2540
2541 setupOverrunTest(vertices);
2542
2543 glPauseTransformFeedback();
2544
2545 // Draw a second time without XFB.
2546 glDrawArrays(GL_POINTS, 0, 6);
2547
2548 // Draw a third time with XFB.
2549 glResumeTransformFeedback();
2550 glDrawArrays(GL_POINTS, 0, 6);
2551
2552 glEndTransformFeedback();
2553
2554 ASSERT_GL_NO_ERROR();
2555
2556 // Verify only the first and third data was output.
2557 const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
2558 mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
2559 const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
2560
2561 size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
2562 VerifyVertexFloats(mapPtrFloat, vertices, 2, numFloats);
2563 }
2564
2565 // Similar to the overrun Pause/Resume test but with more than one Pause and Resume.
TEST_P(TransformFeedbackTest,OverrunWithMultiplePauseAndResume)2566 TEST_P(TransformFeedbackTest, OverrunWithMultiplePauseAndResume)
2567 {
2568
2569 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2570 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2571
2572 // Fails on Adreno Pixel 2 GL drivers. Not a supported configuration.
2573 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAdreno() && IsAndroid());
2574
2575 // Fails on Windows Intel GL drivers. http://anglebug.com/4697
2576 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
2577
2578 // Fails on Mac AMD GL drivers. http://anglebug.com/4775
2579 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsOSX());
2580
2581 // Crashes on Mac Intel GL drivers. http://anglebug.com/4992
2582 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsOSX());
2583
2584 const std::vector<GLfloat> vertices = {
2585 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
2586 -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
2587 };
2588
2589 setupOverrunTest(vertices);
2590
2591 for (int iteration = 0; iteration < 2; ++iteration)
2592 {
2593 // Draw without XFB.
2594 glPauseTransformFeedback();
2595 glDrawArrays(GL_POINTS, 0, 6);
2596
2597 // Draw with XFB.
2598 glResumeTransformFeedback();
2599 glDrawArrays(GL_POINTS, 0, 6);
2600 }
2601
2602 glEndTransformFeedback();
2603
2604 ASSERT_GL_NO_ERROR();
2605
2606 // Verify only the first and third data was output.
2607 const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
2608 mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
2609 const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
2610
2611 size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
2612 VerifyVertexFloats(mapPtrFloat, vertices, 3, numFloats);
2613 }
2614
2615 // Tests begin/draw/end/*bindBuffer*/begin/draw/end.
TEST_P(TransformFeedbackTest,EndThenBindNewBufferAndRestart)2616 TEST_P(TransformFeedbackTest, EndThenBindNewBufferAndRestart)
2617 {
2618
2619 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
2620 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
2621
2622 // Set the program's transform feedback varyings (just gl_Position)
2623 std::vector<std::string> tfVaryings;
2624 tfVaryings.push_back("gl_Position");
2625 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2626
2627 glUseProgram(mProgram);
2628
2629 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
2630 ASSERT_NE(-1, positionLocation);
2631 glEnableVertexAttribArray(positionLocation);
2632
2633 GLBuffer secondBuffer;
2634 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, secondBuffer);
2635 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, nullptr,
2636 GL_STATIC_DRAW);
2637
2638 std::vector<GLfloat> posData1 = {0.1f, 0.0f, 0.0f, 1.0f, 0.2f, 0.0f, 0.0f, 1.0f, 0.3f, 0.0f,
2639 0.0f, 1.0f, 0.4f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f};
2640 std::vector<GLfloat> posData2 = {0.6f, 0.0f, 0.0f, 1.0f, 0.7f, 0.0f, 0.0f, 1.0f, 0.8f, 0.0f,
2641 0.0f, 1.0f, 0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
2642
2643 size_t posBytes = posData1.size() * sizeof(posData1[0]);
2644 ASSERT_EQ(posBytes, posData2.size() * sizeof(posData2[0]));
2645
2646 GLBuffer posBuffer1;
2647 glBindBuffer(GL_ARRAY_BUFFER, posBuffer1);
2648 glBufferData(GL_ARRAY_BUFFER, posBytes, posData1.data(), GL_STATIC_DRAW);
2649
2650 GLBuffer posBuffer2;
2651 glBindBuffer(GL_ARRAY_BUFFER, posBuffer2);
2652 glBufferData(GL_ARRAY_BUFFER, posBytes, posData2.data(), GL_STATIC_DRAW);
2653
2654 // Draw a first time with first buffer.
2655 glBindBuffer(GL_ARRAY_BUFFER, posBuffer1);
2656 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
2657 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2658 glBeginTransformFeedback(GL_POINTS);
2659 glDrawArrays(GL_POINTS, 0, 5);
2660 glEndTransformFeedback();
2661 ASSERT_GL_NO_ERROR();
2662
2663 // Bind second buffer and draw with new data.
2664 glBindBuffer(GL_ARRAY_BUFFER, posBuffer2);
2665 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
2666 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer);
2667 glBeginTransformFeedback(GL_POINTS);
2668 glDrawArrays(GL_POINTS, 0, 5);
2669 glEndTransformFeedback();
2670 ASSERT_GL_NO_ERROR();
2671
2672 // Read back buffer datas.
2673 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
2674 void *posMap1 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, posBytes, GL_MAP_READ_BIT);
2675 ASSERT_NE(posMap1, nullptr);
2676
2677 std::vector<GLfloat> actualData1(posData1.size());
2678 memcpy(actualData1.data(), posMap1, posBytes);
2679
2680 EXPECT_EQ(posData1, actualData1);
2681
2682 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, secondBuffer);
2683 void *posMap2 = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, posBytes, GL_MAP_READ_BIT);
2684 ASSERT_NE(posMap2, nullptr);
2685
2686 std::vector<GLfloat> actualData2(posData2.size());
2687 memcpy(actualData2.data(), posMap2, posBytes);
2688
2689 EXPECT_EQ(posData2, actualData2);
2690 }
2691
2692 // Draw without transform feedback, then with it. In this test, there are no uniforms. Regression
2693 // test based on conformance2/transform_feedback/simultaneous_binding.html for the transform
2694 // feedback emulation path in Vulkan that bundles default uniforms and transform feedback buffers
2695 // in the same descriptor set. A previous bug was that the first non-transform-feedback draw call
2696 // didn't allocate this descriptor set as there were neither uniforms nor transform feedback to be
2697 // updated. A second bug was that the second draw call didn't attempt to update the transform
2698 // feedback buffers, as they were not "dirty".
TEST_P(TransformFeedbackTest,DrawWithoutTransformFeedbackThenWith)2699 TEST_P(TransformFeedbackTest, DrawWithoutTransformFeedbackThenWith)
2700 {
2701 // Fails on Mac Intel GL drivers. http://anglebug.com/4992
2702 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsOSX());
2703
2704 constexpr char kVS[] =
2705 R"(#version 300 es
2706 in float in_value;
2707 out float out_value;
2708
2709 void main() {
2710 out_value = in_value * 2.;
2711 })";
2712
2713 constexpr char kFS[] =
2714 R"(#version 300 es
2715 precision mediump float;
2716 out vec4 unused;
2717 void main() {
2718 unused = vec4(0.5);
2719 })";
2720
2721 std::vector<std::string> tfVaryings;
2722 tfVaryings.push_back("out_value");
2723
2724 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
2725 ASSERT_NE(0u, mProgram);
2726
2727 glUseProgram(mProgram);
2728
2729 GLBuffer vertexBuffer, indexBuffer, xfbBuffer;
2730 GLVertexArray vao;
2731
2732 constexpr std::array<float, 4> kAttribInitData = {1, 2, 3, 4};
2733 constexpr std::array<unsigned short, 4> kIndexInitData = {0, 1, 2, 3};
2734 constexpr std::array<float, 4> kXfbInitData = {0, 0, 0, 0};
2735
2736 // Initialize buffers.
2737 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2738 glBufferData(GL_ARRAY_BUFFER, kAttribInitData.size() * sizeof(kAttribInitData[0]),
2739 kAttribInitData.data(), GL_STATIC_DRAW);
2740 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
2741 glBufferData(GL_ELEMENT_ARRAY_BUFFER, kIndexInitData.size() * sizeof(kIndexInitData[0]),
2742 kIndexInitData.data(), GL_STATIC_DRAW);
2743 glBindBuffer(GL_ARRAY_BUFFER, xfbBuffer);
2744 glBufferData(GL_ARRAY_BUFFER, kXfbInitData.size() * sizeof(kXfbInitData[0]),
2745 kXfbInitData.data(), GL_STATIC_DRAW);
2746
2747 // This tests that having a transform feedback buffer bound in an unbound VAO
2748 // does not affect anything.
2749 GLVertexArray unboundVao;
2750 glBindVertexArray(unboundVao);
2751 glBindBuffer(GL_ARRAY_BUFFER, xfbBuffer);
2752 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
2753 glEnableVertexAttribArray(0);
2754 glVertexAttribPointer(0, 1, GL_FLOAT, false, 0, nullptr);
2755 glBindVertexArray(0);
2756
2757 // Create the real VAO used for the test.
2758 glBindVertexArray(vao);
2759 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2760 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
2761 glEnableVertexAttribArray(0);
2762 glVertexAttribPointer(0, 1, GL_FLOAT, false, 0, nullptr);
2763
2764 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
2765 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer);
2766
2767 // First, issue an indexed draw call without transform feedback.
2768 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_SHORT, 0);
2769
2770 // Then issue a draw call with transform feedback.
2771 glBeginTransformFeedback(GL_POINTS);
2772 glDrawArrays(GL_POINTS, 0, 4);
2773 glEndTransformFeedback();
2774
2775 // Verify transform feedback buffer.
2776 void *mappedBuffer = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
2777 kXfbInitData.size() * sizeof(float), GL_MAP_READ_BIT);
2778 ASSERT_NE(nullptr, mappedBuffer);
2779
2780 float *xfbOutput = static_cast<float *>(mappedBuffer);
2781 for (size_t index = 0; index < kXfbInitData.size(); ++index)
2782 {
2783 EXPECT_EQ(xfbOutput[index], kAttribInitData[index] * 2);
2784 }
2785 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2786
2787 EXPECT_GL_NO_ERROR();
2788 }
2789
2790 // Test that transform feedback with scissor test enabled works.
TEST_P(TransformFeedbackTest,RecordAndDrawWithScissorTest)2791 TEST_P(TransformFeedbackTest, RecordAndDrawWithScissorTest)
2792 {
2793 // http://crbug.com/1135841
2794 ANGLE_SKIP_TEST_IF(IsAMD() && IsOSX());
2795
2796 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
2797 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2798 glDepthMask(GL_TRUE);
2799 glEnable(GL_DEPTH_TEST);
2800
2801 glScissor(0, 0, getWindowWidth() / 2 + 1, getWindowHeight() / 2 + 1);
2802 glEnable(GL_SCISSOR_TEST);
2803
2804 // Set the program's transform feedback varyings (just gl_Position)
2805 std::vector<std::string> tfVaryings;
2806 tfVaryings.push_back("gl_Position");
2807 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2808
2809 glUseProgram(mProgram);
2810
2811 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
2812
2813 // First pass: draw 6 points to the XFB buffer
2814 glEnable(GL_RASTERIZER_DISCARD);
2815
2816 const GLfloat vertices[] = {
2817 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
2818
2819 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
2820 };
2821
2822 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
2823 glEnableVertexAttribArray(positionLocation);
2824
2825 // Bind the buffer for transform feedback output and start transform feedback
2826 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2827 glBeginTransformFeedback(GL_POINTS);
2828
2829 // Create a query to check how many primitives were written
2830 GLQuery primitivesWrittenQuery;
2831 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
2832
2833 glDrawArrays(GL_POINTS, 0, 3);
2834 glDrawArrays(GL_POINTS, 3, 3);
2835
2836 glDisableVertexAttribArray(positionLocation);
2837 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2838 // End the query and transform feedback
2839 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
2840 glEndTransformFeedback();
2841
2842 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
2843
2844 glDisable(GL_RASTERIZER_DISCARD);
2845
2846 // Check how many primitives were written and verify that some were written even if
2847 // no pixels were rendered
2848 GLuint primitivesWritten = 0;
2849 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
2850 EXPECT_GL_NO_ERROR();
2851
2852 EXPECT_EQ(6u, primitivesWritten);
2853
2854 // Second pass: draw from the feedback buffer
2855
2856 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
2857 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
2858 glEnableVertexAttribArray(positionLocation);
2859
2860 glDrawArrays(GL_TRIANGLES, 0, 6);
2861
2862 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
2863 EXPECT_PIXEL_EQ(getWindowWidth() / 2 + 1, getWindowHeight() / 2 + 1, 0, 0, 0, 255);
2864 EXPECT_GL_NO_ERROR();
2865 }
2866
2867 // Test XFB with depth write enabled.
2868 class TransformFeedbackWithDepthBufferTest : public TransformFeedbackTest
2869 {
2870 public:
TransformFeedbackWithDepthBufferTest()2871 TransformFeedbackWithDepthBufferTest() : TransformFeedbackTest() { setConfigDepthBits(24); }
2872 };
2873
TEST_P(TransformFeedbackWithDepthBufferTest,RecordAndDrawWithDepthWriteEnabled)2874 TEST_P(TransformFeedbackWithDepthBufferTest, RecordAndDrawWithDepthWriteEnabled)
2875 {
2876 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2877 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2878 glDepthMask(GL_TRUE);
2879 glEnable(GL_DEPTH_TEST);
2880
2881 // Set the program's transform feedback varyings (just gl_Position)
2882 std::vector<std::string> tfVaryings;
2883 tfVaryings.push_back("gl_Position");
2884 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
2885
2886 glUseProgram(mProgram);
2887
2888 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
2889
2890 // First pass: draw 6 points to the XFB buffer
2891 glEnable(GL_RASTERIZER_DISCARD);
2892
2893 const GLfloat vertices[] = {
2894 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
2895
2896 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
2897 };
2898
2899 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
2900 glEnableVertexAttribArray(positionLocation);
2901
2902 // Bind the buffer for transform feedback output and start transform feedback
2903 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
2904 glBeginTransformFeedback(GL_POINTS);
2905
2906 // Create a query to check how many primitives were written
2907 GLQuery primitivesWrittenQuery;
2908 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
2909
2910 glDrawArrays(GL_POINTS, 0, 3);
2911 glDrawArrays(GL_POINTS, 3, 3);
2912
2913 glDisableVertexAttribArray(positionLocation);
2914 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2915 // End the query and transform feedback
2916 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
2917 glEndTransformFeedback();
2918
2919 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
2920
2921 glDisable(GL_RASTERIZER_DISCARD);
2922
2923 // Check how many primitives were written and verify that some were written even if
2924 // no pixels were rendered
2925 GLuint primitivesWritten = 0;
2926 glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
2927 EXPECT_GL_NO_ERROR();
2928
2929 EXPECT_EQ(6u, primitivesWritten);
2930
2931 // Second pass: draw from the feedback buffer
2932
2933 glBindBuffer(GL_ARRAY_BUFFER, mTransformFeedbackBuffer);
2934 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
2935 glEnableVertexAttribArray(positionLocation);
2936
2937 glDrawArrays(GL_TRIANGLES, 0, 6);
2938
2939 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
2940 EXPECT_GL_NO_ERROR();
2941 }
2942
2943 // Test that changing the transform feedback binding offset works.
TEST_P(TransformFeedbackTest,RecordTwiceWithBindingOffsetChange)2944 TEST_P(TransformFeedbackTest, RecordTwiceWithBindingOffsetChange)
2945 {
2946 constexpr char kVS[] = R"(
2947 varying vec4 v;
2948
2949 void main()
2950 {
2951 v = vec4(0.25, 0.5, 0.75, 1.0);
2952 })";
2953
2954 constexpr char kFS[] = R"(
2955 precision mediump float;
2956 void main()
2957 {
2958 gl_FragColor = vec4(0);
2959 })";
2960
2961 // Capture the varying "v"
2962 const std::vector<std::string> tfVaryings = {"v"};
2963 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
2964 EXPECT_GL_NO_ERROR();
2965
2966 glUseProgram(program);
2967
2968 constexpr std::array<GLenum, 3> kUsages = {GL_STATIC_DRAW, GL_STREAM_DRAW, GL_DYNAMIC_DRAW};
2969
2970 constexpr uint32_t kVaryingSize = 4;
2971 constexpr uint32_t kFirstOffset = 8;
2972 constexpr uint32_t kSecondOffset = 24;
2973 constexpr uint32_t kBufferSize = 40;
2974
2975 const std::vector<float> initialData(kBufferSize, 0);
2976 std::vector<float> expectedData = initialData;
2977
2978 expectedData[kFirstOffset + 0] = expectedData[kSecondOffset + 0] = 0.25f;
2979 expectedData[kFirstOffset + 1] = expectedData[kSecondOffset + 1] = 0.5f;
2980 expectedData[kFirstOffset + 2] = expectedData[kSecondOffset + 2] = 0.75f;
2981 expectedData[kFirstOffset + 3] = expectedData[kSecondOffset + 3] = 1.0f;
2982
2983 for (GLenum usage : kUsages)
2984 {
2985 GLTransformFeedback xfb;
2986 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
2987
2988 GLBuffer xfbBuffer;
2989 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffer);
2990 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, kBufferSize * sizeof(float), initialData.data(),
2991 GL_DYNAMIC_DRAW);
2992
2993 // Record into first offset
2994 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer, kFirstOffset * sizeof(float),
2995 kVaryingSize * sizeof(float));
2996 glBeginTransformFeedback(GL_POINTS);
2997 glDrawArrays(GL_POINTS, 0, 1);
2998 glEndTransformFeedback();
2999
3000 // Record into second offset
3001 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer, kSecondOffset * sizeof(float),
3002 kVaryingSize * sizeof(float));
3003 glBeginTransformFeedback(GL_POINTS);
3004 glDrawArrays(GL_POINTS, 0, 1);
3005 glEndTransformFeedback();
3006
3007 const float *bufferData = static_cast<float *>(glMapBufferRange(
3008 GL_TRANSFORM_FEEDBACK_BUFFER, 0, kBufferSize * sizeof(float), GL_MAP_READ_BIT));
3009 EXPECT_GL_NO_ERROR();
3010
3011 for (uint32_t index = 0; index < kBufferSize; ++index)
3012 {
3013 EXPECT_NEAR(bufferData[index], expectedData[index], 1e-6)
3014 << "index: " << index << " usage: " << usage;
3015 }
3016
3017 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3018 }
3019 }
3020
3021 class TransformFeedbackTestES32 : public TransformFeedbackTest
3022 {
3023 public:
TransformFeedbackTestES32()3024 TransformFeedbackTestES32() : TransformFeedbackTest()
3025 {
3026 setConfigDepthBits(24);
3027 setConfigStencilBits(8);
3028 }
3029 };
3030
3031 // Test that simultaneous use of transform feedback primitives written and primitives generated
3032 // queries works.
TEST_P(TransformFeedbackTestES32,PrimitivesWrittenAndGenerated)3033 TEST_P(TransformFeedbackTestES32, PrimitivesWrittenAndGenerated)
3034 {
3035 // TODO(anglebug.com/4533) This fails after the upgrade to the 26.20.100.7870 driver.
3036 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
3037
3038 // No ES3.2 support on our bots. http://anglebug.com/5435
3039 ANGLE_SKIP_TEST_IF(IsPixel2() && IsVulkan());
3040
3041 // No VK_EXT_transform_feedback support on the following configurations.
3042 // http://anglebug.com/5435
3043 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows());
3044 ANGLE_SKIP_TEST_IF(IsVulkan() && IsNVIDIA() && IsWindows7());
3045
3046 // http://anglebug.com/5539
3047 ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux());
3048
3049 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
3050 glClear(GL_COLOR_BUFFER_BIT);
3051
3052 // Set the program's transform feedback varyings (just gl_Position)
3053 std::vector<std::string> tfVaryings;
3054 tfVaryings.push_back("gl_Position");
3055 compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
3056
3057 glUseProgram(mProgram);
3058
3059 GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
3060
3061 glEnable(GL_RASTERIZER_DISCARD);
3062
3063 const GLfloat vertices[] = {
3064 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f, -1.0f, 1.0f, 0.5f,
3065 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f, -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f,
3066 1.0f, -1.0f, 0.5f, -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
3067 };
3068
3069 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
3070 glEnableVertexAttribArray(positionLocation);
3071
3072 // Bind the buffer for transform feedback output and start transform feedback
3073 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
3074 glBeginTransformFeedback(GL_POINTS);
3075 EXPECT_GL_NO_ERROR();
3076
3077 // Create a number of queries. The test overview is as follows (PW = PrimitivesWritten, PG =
3078 // Primitives Generated):
3079 //
3080 // PW0 begin
3081 // - Draw 3
3082 // PG0 begin
3083 // - Draw 4
3084 // PW0 end
3085 // - Draw 5
3086 // - Copy
3087 // - Draw 6
3088 // PW1 begin
3089 // - Draw 7
3090 // - Copy
3091 // - Draw 8
3092 // PG0 end
3093 // PG1 begin
3094 // - Draw 9
3095 // - Copy
3096 // PW1 end
3097 // - Draw 10
3098 // - Copy
3099 // PG1 end
3100 // PW2 begin
3101 // PG2 begin
3102 // - Draw 11
3103 // - Copy
3104 // - Draw 12
3105 // PG2 end
3106 // PW2 end
3107 //
3108 // This tests a variety of scenarios where either of PW or PG is active or not when the other
3109 // begins or ends, as well as testing render pass restarts with the queries active and begin and
3110 // end of queries outside or mid render pass.
3111 constexpr size_t kQueryCount = 3;
3112 GLQuery primitivesWrittenQueries[kQueryCount];
3113 GLQuery primitivesGeneratedQueries[kQueryCount];
3114
3115 GLTexture texture;
3116 glBindTexture(GL_TEXTURE_2D, texture);
3117
3118 /* PG PW */
3119 /* / */ glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQueries[0]);
3120 /* | */ glDrawArrays(GL_POINTS, 0, 3);
3121 /* / 0 */ glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQueries[0]);
3122 /* | | */ glDrawArrays(GL_POINTS, 0, 4);
3123 /* | \ */ glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
3124 /* | */ glDrawArrays(GL_POINTS, 0, 5);
3125 /* | */ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3126 /* 0 */ glDrawArrays(GL_POINTS, 0, 6);
3127 /* | / */ glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQueries[1]);
3128 /* | | */ glDrawArrays(GL_POINTS, 0, 7);
3129 /* | | */ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3130 /* | | */ glDrawArrays(GL_POINTS, 0, 8);
3131 /* \ 1 */ glEndQuery(GL_PRIMITIVES_GENERATED);
3132 /* / | */ glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQueries[1]);
3133 /* | | */ glDrawArrays(GL_POINTS, 0, 9);
3134 /* | | */ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3135 /* 1 \ */ glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
3136 /* | */ glDrawArrays(GL_POINTS, 0, 10);
3137 /* | */ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3138 /* \ */ glEndQuery(GL_PRIMITIVES_GENERATED);
3139 /* / */ glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQueries[2]);
3140 /* / | */ glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQueries[2]);
3141 /* | | */ glDrawArrays(GL_POINTS, 0, 11);
3142 /* 2 2 */ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3143 /* | | */ glDrawArrays(GL_POINTS, 0, 12);
3144 /* \ | */ glEndQuery(GL_PRIMITIVES_GENERATED);
3145 /* \ */ glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
3146
3147 glEndTransformFeedback();
3148 EXPECT_GL_NO_ERROR();
3149
3150 // Check that the queries have correct results. Verify the first of each query with
3151 // GL_QUERY_RESULT_AVAILABLE for no particular reason other than testing different paths.
3152 GLuint readyPW = GL_FALSE;
3153 GLuint readyPG = GL_FALSE;
3154 while (readyPW == GL_FALSE || readyPG == GL_FALSE)
3155 {
3156 glGetQueryObjectuiv(primitivesWrittenQueries[0], GL_QUERY_RESULT_AVAILABLE, &readyPW);
3157 glGetQueryObjectuiv(primitivesGeneratedQueries[0], GL_QUERY_RESULT_AVAILABLE, &readyPG);
3158 }
3159 EXPECT_GL_NO_ERROR();
3160
3161 constexpr GLuint kPrimitivesWrittenExpected[kQueryCount] = {
3162 3 + 4,
3163 7 + 8 + 9,
3164 11 + 12,
3165 };
3166 constexpr GLuint kPrimitivesGeneratedExpected[kQueryCount] = {
3167 4 + 5 + 6 + 7 + 8,
3168 9 + 10,
3169 11 + 12,
3170 };
3171
3172 for (size_t queryIndex = 0; queryIndex < kQueryCount; ++queryIndex)
3173 {
3174 GLuint primitivesWritten = 0;
3175 glGetQueryObjectuiv(primitivesWrittenQueries[queryIndex], GL_QUERY_RESULT,
3176 &primitivesWritten);
3177
3178 GLuint primitivesGenerated = 0;
3179 glGetQueryObjectuiv(primitivesGeneratedQueries[queryIndex], GL_QUERY_RESULT,
3180 &primitivesGenerated);
3181 EXPECT_GL_NO_ERROR();
3182
3183 EXPECT_EQ(primitivesWritten, kPrimitivesWrittenExpected[queryIndex]) << queryIndex;
3184 EXPECT_EQ(primitivesGenerated, kPrimitivesGeneratedExpected[queryIndex]) << queryIndex;
3185 }
3186 }
3187
3188 // Test that primitives generated query and rasterizer discard interact well.
TEST_P(TransformFeedbackTestES32,PrimitivesGeneratedVsRasterizerDiscard)3189 TEST_P(TransformFeedbackTestES32, PrimitivesGeneratedVsRasterizerDiscard)
3190 {
3191 // No ES3.2 support on our bots. http://anglebug.com/5435
3192 ANGLE_SKIP_TEST_IF(IsPixel2() && IsVulkan());
3193
3194 // No pipelineStatisticsQuery or VK_EXT_transform_feedback support on the following
3195 // configurations. http://anglebug.com/5435
3196 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows());
3197 ANGLE_SKIP_TEST_IF(IsVulkan() && IsNVIDIA() && IsWindows7());
3198
3199 // http://anglebug.com/5539
3200 ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux());
3201
3202 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
3203 glClearDepthf(0.1f);
3204 glClearStencil(0x5A);
3205 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3206
3207 ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
3208 glUseProgram(drawColor);
3209 GLint colorUniformLocation =
3210 glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
3211 ASSERT_NE(colorUniformLocation, -1);
3212
3213 // First, disable all output.
3214 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3215
3216 glEnable(GL_DEPTH_TEST);
3217 glDepthFunc(GL_ALWAYS);
3218 glDepthMask(GL_FALSE);
3219
3220 glEnable(GL_STENCIL_TEST);
3221 glStencilFunc(GL_ALWAYS, 0x3E, 0xFF);
3222 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3223 glStencilMask(0xFF);
3224
3225 int w = getWindowWidth();
3226 int h = getWindowHeight();
3227
3228 // Render to a part of the output. It should produce nothing.
3229 glScissor(0, 0, w / 4, h / 2);
3230 glEnable(GL_SCISSOR_TEST);
3231 glUniform4f(colorUniformLocation, 0.1f, 0.2f, 0.3f, 0.4f);
3232 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3233
3234 // Then enable the primitives generated query, and issue another draw call. Still no output
3235 // should be produced.
3236 GLQuery primitivesGeneratedQuery;
3237 glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQuery);
3238 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3239
3240 // Enable rasterizer discard. Still no output should be produced.
3241 glEnable(GL_RASTERIZER_DISCARD);
3242 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3243
3244 // Enable color output. Render to another part. No output should be produced.
3245 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3246 glScissor(w / 4, 0, w / 4, h / 2);
3247 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3248
3249 // Enable depth and stencil output. Render to another part. No output should be produced.
3250 glDepthMask(GL_TRUE);
3251 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
3252 glScissor(w / 2, 0, w / 4, h / 2);
3253 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3254
3255 // Disable rasterizer discard. Render to another part. Should produce output.
3256 glDisable(GL_RASTERIZER_DISCARD);
3257 glScissor(3 * w / 4, 0, w / 4, h / 2);
3258 glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
3259 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3260 ASSERT_GL_NO_ERROR();
3261
3262 // Break the render pass by validating the results. Note that the query is still active, and
3263 // rasterizer discard is not.
3264 EXPECT_PIXEL_RECT_EQ(0, 0, 3 * w / 4, h / 2, GLColor::blue);
3265 EXPECT_PIXEL_RECT_EQ(3 * w / 4, 0, w / 4, h / 2, GLColor::red);
3266
3267 // Start another render pass. Render to the another part. Should produce output.
3268 glScissor(0, h / 2, w / 4, h / 2);
3269 glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
3270 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3271
3272 // Enable rasterizer discard. Render to another part. No output should be produced.
3273 glEnable(GL_RASTERIZER_DISCARD);
3274 glScissor(w / 4, h / 2, w / 4, h / 2);
3275 glUniform4f(colorUniformLocation, 0.1f, 0.2f, 0.3f, 0.4f);
3276 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3277 ASSERT_GL_NO_ERROR();
3278
3279 // Break the render pass by validating the results. Note that the query is still active, and
3280 // so is rasterizer discard.
3281 EXPECT_PIXEL_RECT_EQ(0, h / 2, w / 4, h / 2, GLColor::green);
3282 EXPECT_PIXEL_RECT_EQ(w / 4, h / 2, w / 4, h / 2, GLColor::blue);
3283
3284 // Start another render pass. Render to the another part. No output should be produced.
3285 glScissor(w / 2, h / 2, w / 4, h / 2);
3286 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3287
3288 // Disable rasterizer discard. Render to another part. Should produce output.
3289 glDisable(GL_RASTERIZER_DISCARD);
3290 glScissor(3 * w / 4, h / 2, w / 4, h / 2);
3291 glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
3292 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3293 ASSERT_GL_NO_ERROR();
3294
3295 // Verify color results
3296 EXPECT_PIXEL_RECT_EQ(w / 2, h / 2, w / 4, h / 2, GLColor::blue);
3297 EXPECT_PIXEL_RECT_EQ(3 * w / 4, h / 2, w / 4, h / 2, GLColor::yellow);
3298
3299 // Verify that depth/stencil has correct results.
3300 glDepthFunc(GL_LESS);
3301 glStencilFunc(GL_EQUAL, 0x3E, 0xFF);
3302
3303 glScissor(0, 0, w, h);
3304 glUniform4f(colorUniformLocation, 0.0f, 1.0f, 1.0f, 1.0f);
3305 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.55f);
3306 ASSERT_GL_NO_ERROR();
3307
3308 // Validate that depth/stencil is modified only where color is modified above.
3309 EXPECT_PIXEL_RECT_EQ(0, 0, 3 * w / 4, h / 2, GLColor::blue);
3310 EXPECT_PIXEL_RECT_EQ(3 * w / 4, 0, w / 4, h / 2, GLColor::cyan);
3311
3312 EXPECT_PIXEL_RECT_EQ(0, h / 2, w / 4, h / 2, GLColor::cyan);
3313 EXPECT_PIXEL_RECT_EQ(w / 4, h / 2, w / 4, h / 2, GLColor::blue);
3314
3315 EXPECT_PIXEL_RECT_EQ(w / 2, h / 2, w / 4, h / 2, GLColor::blue);
3316 EXPECT_PIXEL_RECT_EQ(3 * w / 4, h / 2, w / 4, h / 2, GLColor::cyan);
3317
3318 // End the query and verify the count.
3319 glEndQuery(GL_PRIMITIVES_GENERATED);
3320 EXPECT_GL_NO_ERROR();
3321
3322 GLuint primitivesGenerated = 0;
3323 glGetQueryObjectuiv(primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGenerated);
3324 EXPECT_GL_NO_ERROR();
3325
3326 EXPECT_EQ(primitivesGenerated, 20u); // 10 draw calls, 2 triangles each.
3327 }
3328
3329 // Test that multiple primitives generated querys and rasterizer discard interact well.
TEST_P(TransformFeedbackTestES32,MultiPrimitivesGeneratedVsRasterizerDiscard)3330 TEST_P(TransformFeedbackTestES32, MultiPrimitivesGeneratedVsRasterizerDiscard)
3331 {
3332 // No ES3.2 support on our bots. http://anglebug.com/5435
3333 ANGLE_SKIP_TEST_IF(IsPixel2() && IsVulkan());
3334
3335 // No pipelineStatisticsQuery or VK_EXT_transform_feedback support on the following
3336 // configurations. http://anglebug.com/5435
3337 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows());
3338 ANGLE_SKIP_TEST_IF(IsVulkan() && IsNVIDIA() && IsWindows7());
3339
3340 // http://anglebug.com/5539
3341 ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux());
3342
3343 ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
3344 glUseProgram(drawColor);
3345
3346 // Enable rasterizer discard.
3347 glEnable(GL_RASTERIZER_DISCARD);
3348
3349 // Start first primitives generated query
3350 GLQuery primitivesGeneratedQuery;
3351 glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQuery);
3352 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3353 ASSERT_GL_NO_ERROR();
3354
3355 // End the query and verify the count.
3356 glEndQuery(GL_PRIMITIVES_GENERATED);
3357 ASSERT_GL_NO_ERROR();
3358
3359 GLuint primitivesGenerated = 0;
3360 glGetQueryObjectuiv(primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGenerated);
3361 ASSERT_GL_NO_ERROR();
3362
3363 EXPECT_EQ(primitivesGenerated, 2u); // 1 draw call, 2 triangles each.
3364
3365 // Start second primitives generated query
3366 glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQuery);
3367 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3368 ASSERT_GL_NO_ERROR();
3369
3370 // End the query and verify the count.
3371 glEndQuery(GL_PRIMITIVES_GENERATED);
3372 ASSERT_GL_NO_ERROR();
3373
3374 primitivesGenerated = 0;
3375 glGetQueryObjectuiv(primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGenerated);
3376 ASSERT_GL_NO_ERROR();
3377
3378 EXPECT_EQ(primitivesGenerated, 2u); // 1 draw call, 2 triangles each.
3379 glDisable(GL_RASTERIZER_DISCARD);
3380 }
3381
3382 // Test that primitives generated query and rasterizer discard interact well when the framebuffer
3383 // changes.
TEST_P(TransformFeedbackTestES32,PrimitivesGeneratedVsRasterizerDiscardAndFramebufferChange)3384 TEST_P(TransformFeedbackTestES32, PrimitivesGeneratedVsRasterizerDiscardAndFramebufferChange)
3385 {
3386 // No ES3.2 support on our bots. http://anglebug.com/5435
3387 ANGLE_SKIP_TEST_IF(IsPixel2() && IsVulkan());
3388
3389 // No pipelineStatisticsQuery or VK_EXT_transform_feedback support on the following
3390 // configurations. http://anglebug.com/5435
3391 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows());
3392 ANGLE_SKIP_TEST_IF(IsVulkan() && IsNVIDIA() && IsWindows7());
3393
3394 // http://anglebug.com/5539
3395 ANGLE_SKIP_TEST_IF(IsVulkan() && IsLinux());
3396
3397 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
3398 glClearDepthf(0.1f);
3399 glClearStencil(0x5A);
3400 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3401
3402 constexpr GLsizei kFBOSize = 16;
3403 GLTexture colorTexture;
3404 glBindTexture(GL_TEXTURE_2D, colorTexture);
3405 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kFBOSize, kFBOSize);
3406
3407 GLTexture depthStencilTexture;
3408 glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
3409 glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, kFBOSize, kFBOSize);
3410
3411 GLFramebuffer fbo;
3412 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3413 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
3414 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
3415 depthStencilTexture, 0);
3416 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
3417 ASSERT_GL_NO_ERROR();
3418
3419 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3420 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3421
3422 ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
3423 glUseProgram(drawColor);
3424 GLint colorUniformLocation =
3425 glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
3426 ASSERT_NE(colorUniformLocation, -1);
3427
3428 // First, disable all output.
3429 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3430
3431 glEnable(GL_DEPTH_TEST);
3432 glDepthFunc(GL_ALWAYS);
3433 glDepthMask(GL_FALSE);
3434
3435 glEnable(GL_STENCIL_TEST);
3436 glStencilFunc(GL_ALWAYS, 0x3E, 0xFF);
3437 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3438 glStencilMask(0xFF);
3439
3440 int w = getWindowWidth();
3441 int h = getWindowHeight();
3442
3443 // Render to a part of the output. It should produce nothing.
3444 glScissor(0, 0, w / 4, h);
3445 glEnable(GL_SCISSOR_TEST);
3446 glUniform4f(colorUniformLocation, 0.1f, 0.2f, 0.3f, 0.4f);
3447 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3448
3449 // Then enable the primitives generated query, and issue another draw call. Still no output
3450 // should be produced.
3451 GLQuery primitivesGeneratedQuery;
3452 glBeginQuery(GL_PRIMITIVES_GENERATED, primitivesGeneratedQuery);
3453 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3454
3455 // Enable rasterizer discard. Still no output should be produced.
3456 glEnable(GL_RASTERIZER_DISCARD);
3457 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3458
3459 // Enable color output. Render to another part. No output should be produced.
3460 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3461 glScissor(w / 4, 0, w / 4, h);
3462 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3463
3464 // Enable depth and stencil output and disable rasterizer discard. Render to another part.
3465 // Should produce output.
3466 glDisable(GL_RASTERIZER_DISCARD);
3467 glDepthMask(GL_TRUE);
3468 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
3469 glScissor(w / 2, 0, w / 4, h);
3470 glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
3471 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3472
3473 // Enable rasterizer discard again. Render to another part. No output should be produced.
3474 glEnable(GL_RASTERIZER_DISCARD);
3475 glScissor(3 * w / 4, 0, w / 4, h);
3476 glUniform4f(colorUniformLocation, 0.1f, 0.2f, 0.3f, 0.4f);
3477 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3478 ASSERT_GL_NO_ERROR();
3479
3480 // Break the render pass by validating the results. Note that the query is still active, and
3481 // so is rasterizer discard.
3482 EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h, GLColor::blue);
3483 EXPECT_PIXEL_RECT_EQ(3 * w / 4, 0, w / 4, h, GLColor::blue);
3484 EXPECT_PIXEL_RECT_EQ(w / 2, 0, w / 4, h, GLColor::red);
3485
3486 // Switch to another framebuffer.
3487 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3488
3489 // Start another render pass. Render to a part of the framebuffer. No output should be
3490 // produced.
3491 glScissor(0, 0, kFBOSize / 2, kFBOSize);
3492 glUniform4f(colorUniformLocation, 0.4f, 0.3f, 0.2f, 0.1f);
3493 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3494
3495 // Enable rasterizer discard. Render to another part. Should produce output.
3496 glDisable(GL_RASTERIZER_DISCARD);
3497 glScissor(kFBOSize / 2, 0, kFBOSize / 2, kFBOSize);
3498 glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
3499 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3500
3501 // Disable color write. Render to the same part. No output should be produced.
3502 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3503 glUniform4f(colorUniformLocation, 0.4f, 0.3f, 0.2f, 0.1f);
3504 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.6f);
3505 ASSERT_GL_NO_ERROR();
3506
3507 // Break the render pass by validating the results. Note that the query is still active, and
3508 // rasterizer discard is not.
3509 EXPECT_PIXEL_RECT_EQ(0, 0, kFBOSize / 2, kFBOSize, GLColor::blue);
3510 EXPECT_PIXEL_RECT_EQ(kFBOSize / 2, 0, kFBOSize / 2, kFBOSize, GLColor::green);
3511
3512 // Verify that depth/stencil has correct results in the FBO.
3513 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3514 glDepthFunc(GL_LESS);
3515 glStencilFunc(GL_EQUAL, 0x3E, 0xFF);
3516
3517 glScissor(0, 0, kFBOSize, kFBOSize);
3518 glUniform4f(colorUniformLocation, 1.0f, 0.0f, 1.0f, 1.0f);
3519 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.55f);
3520
3521 // Validate that depth/stencil is modified only where color is modified above.
3522 EXPECT_PIXEL_RECT_EQ(0, 0, kFBOSize / 2, kFBOSize, GLColor::blue);
3523 EXPECT_PIXEL_RECT_EQ(kFBOSize / 2, 0, kFBOSize / 2, kFBOSize, GLColor::magenta);
3524
3525 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3526
3527 // Verify that depth/stencil has correct results.
3528 glScissor(0, 0, w, h);
3529 glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
3530 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.55f);
3531
3532 // Validate that depth/stencil is modified only where color is modified above.
3533 EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h, GLColor::blue);
3534 EXPECT_PIXEL_RECT_EQ(3 * w / 4, 0, w / 4, h, GLColor::blue);
3535 EXPECT_PIXEL_RECT_EQ(w / 2, 0, w / 4, h, GLColor::yellow);
3536
3537 // End the query and verify the count.
3538 glEndQuery(GL_PRIMITIVES_GENERATED);
3539 EXPECT_GL_NO_ERROR();
3540
3541 GLuint primitivesGenerated = 0;
3542 glGetQueryObjectuiv(primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGenerated);
3543 EXPECT_GL_NO_ERROR();
3544
3545 EXPECT_EQ(primitivesGenerated, 20u); // 10 draw calls, 2 triangles each.
3546 }
3547
3548 class TransformFeedbackTestIOBlocks : public TransformFeedbackTestES31
3549 {};
3550
3551 // Verify that capture of I/O block fields works, both when the instance name is specified and when
3552 // not. This test uses interleaved components.
TEST_P(TransformFeedbackTestIOBlocks,Interleaved)3553 TEST_P(TransformFeedbackTestIOBlocks, Interleaved)
3554 {
3555 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
3556
3557 // http://anglebug.com/5488
3558 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
3559 // http://anglebug.com/5493
3560 ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsVulkan());
3561
3562 constexpr char kVS[] = R"(#version 310 es
3563 #extension GL_EXT_shader_io_blocks : require
3564
3565 out VSBlock1
3566 {
3567 vec4 a;
3568 vec4 b[2];
3569 } blockOut1;
3570
3571 out VSBlock2
3572 {
3573 vec4 c;
3574 mat3 d;
3575 vec4 e;
3576 };
3577
3578 out vec4 looseVarying;
3579
3580 void main()
3581 {
3582 blockOut1.a = vec4(0.15, 0.18, 0.21, 0.24);
3583 blockOut1.b[0] = vec4(0.27, 0.30, 0.33, 0.36);
3584 blockOut1.b[1] = vec4(0.39, 0.42, 0.45, 0.48);
3585 c = vec4(0.51, 0.54, 0.57, 0.6);
3586 d = mat3(vec3(0.63, 0.66, 0.69), vec3(0.72, 0.75, 0.78), vec3(0.81, 0.84, 0.87));
3587 e = vec4(0.9, 0.93, 0.96, 0.99);
3588 looseVarying = vec4(0.25, 0.5, 0.75, 1.0);
3589 })";
3590
3591 constexpr char kFS[] = R"(#version 310 es
3592 #extension GL_EXT_shader_io_blocks : require
3593 precision mediump float;
3594
3595 layout(location = 0) out mediump vec4 color;
3596
3597 in VSBlock2
3598 {
3599 vec4 c;
3600 mat3 d;
3601 vec4 e;
3602 };
3603
3604 void main()
3605 {
3606 color = vec4(c.x, d[0].y, e.z, 1.0);
3607 })";
3608
3609 std::vector<std::string> tfVaryings = {"VSBlock1.b", "d", "looseVarying"};
3610 constexpr size_t kCapturedVaryingsCount = 3;
3611 constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {8, 9, 4};
3612 const std::vector<float> kExpected[kCapturedVaryingsCount] = {
3613 {0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
3614 {0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
3615 {0.25, 0.5, 0.75, 1.0},
3616 };
3617
3618 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
3619 EXPECT_GL_NO_ERROR();
3620
3621 GLTransformFeedback xfb;
3622 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
3623
3624 GLBuffer xfbBuffer;
3625
3626 size_t totalSize = 0;
3627 for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
3628 {
3629 totalSize += kCaptureSizes[index];
3630 }
3631
3632 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffer);
3633 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, totalSize * sizeof(float), nullptr, GL_STATIC_DRAW);
3634 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer);
3635
3636 glUseProgram(program);
3637
3638 glBeginTransformFeedback(GL_POINTS);
3639 glDrawArrays(GL_POINTS, 0, 1);
3640 glEndTransformFeedback();
3641
3642 const float *bufferData = static_cast<float *>(glMapBufferRange(
3643 GL_TRANSFORM_FEEDBACK_BUFFER, 0, totalSize * sizeof(float), GL_MAP_READ_BIT));
3644
3645 size_t currentOffset = 0;
3646 for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
3647 {
3648 for (size_t component = 0; component < kCaptureSizes[index]; ++component)
3649 {
3650 EXPECT_NEAR(bufferData[currentOffset + component], kExpected[index][component], 0.001f)
3651 << index << " " << component;
3652 }
3653 currentOffset += kCaptureSizes[index];
3654 }
3655
3656 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3657 }
3658
3659 // Verify that capture of I/O block fields works. This test uses separate components.
TEST_P(TransformFeedbackTestIOBlocks,Separate)3660 TEST_P(TransformFeedbackTestIOBlocks, Separate)
3661 {
3662 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
3663
3664 // http://anglebug.com/5487
3665 ANGLE_SKIP_TEST_IF(IsLinux() && (IsIntel() || IsAMD()) && IsOpenGL());
3666
3667 // http://anglebug.com/5488
3668 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
3669
3670 // http://anglebug.com/5493
3671 ANGLE_SKIP_TEST_IF(IsLinux() && (IsAMD() || IsARM()) && IsVulkan());
3672
3673 constexpr char kVS[] = R"(#version 310 es
3674 #extension GL_EXT_shader_io_blocks : require
3675
3676 out VSBlock
3677 {
3678 float a;
3679 vec2 b;
3680 };
3681
3682 out float c;
3683
3684 void main()
3685 {
3686 a = 0.25;
3687 b = vec2(0.5, 0.75);
3688 c = 1.0;
3689 })";
3690
3691 constexpr char kFS[] = R"(#version 310 es
3692 #extension GL_EXT_shader_io_blocks : require
3693 precision mediump float;
3694
3695 layout(location = 0) out mediump vec4 color;
3696
3697 in VSBlock
3698 {
3699 float a;
3700 vec2 b;
3701 };
3702
3703 void main()
3704 {
3705 color = vec4(a, b, 1.0);
3706 })";
3707
3708 std::vector<std::string> tfVaryings = {"a", "b", "c"};
3709 constexpr size_t kCapturedVaryingsCount = 3;
3710 constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {1, 2, 1};
3711 const std::vector<float> kExpected[kCapturedVaryingsCount] = {
3712 {0.25},
3713 {0.5, 0.75},
3714 {1.0},
3715 };
3716
3717 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
3718 EXPECT_GL_NO_ERROR();
3719
3720 GLTransformFeedback xfb;
3721 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
3722
3723 std::array<GLBuffer, kCapturedVaryingsCount> xfbBuffers;
3724
3725 for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
3726 {
3727 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffers[index]);
3728 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, kCaptureSizes[index] * sizeof(float), nullptr,
3729 GL_STATIC_DRAW);
3730 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index, xfbBuffers[index]);
3731 }
3732
3733 glUseProgram(program);
3734
3735 glBeginTransformFeedback(GL_POINTS);
3736 glDrawArrays(GL_POINTS, 0, 1);
3737 glEndTransformFeedback();
3738
3739 for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
3740 {
3741 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffers[index]);
3742
3743 const float *bufferData = static_cast<float *>(
3744 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, kCaptureSizes[index] * sizeof(float),
3745 GL_MAP_READ_BIT));
3746
3747 for (size_t component = 0; component < kCaptureSizes[index]; ++component)
3748 {
3749 EXPECT_NEAR(bufferData[component], kExpected[index][component], 0.001f)
3750 << index << " " << component;
3751 }
3752
3753 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3754 }
3755 }
3756
3757 // Tests transform feedback with no buffer bound.
TEST_P(TransformFeedbackTest,MissingBuffer)3758 TEST_P(TransformFeedbackTest, MissingBuffer)
3759 {
3760 constexpr char kVS[] = R"(#version 300 es
3761 in vec2 position;
3762 in float attrib;
3763 out float varyingAttrib;
3764 void main() {
3765 gl_Position = vec4(position, 0, 1);
3766 varyingAttrib = attrib;
3767 })";
3768
3769 const std::vector<std::string> tfVaryings = {"varyingAttrib"};
3770 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(prog, kVS, essl3_shaders::fs::Green(), tfVaryings,
3771 GL_INTERLEAVED_ATTRIBS);
3772 glUseProgram(prog);
3773
3774 GLTransformFeedback xfb;
3775 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
3776 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
3777
3778 std::vector<float> attribData;
3779 for (unsigned int cnt = 0; cnt < 100; ++cnt)
3780 {
3781 attribData.push_back(static_cast<float>(cnt));
3782 }
3783
3784 GLint attribLocation = glGetAttribLocation(prog, "attrib");
3785 ASSERT_NE(-1, attribLocation);
3786
3787 glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, &attribData[0]);
3788 glEnableVertexAttribArray(attribLocation);
3789
3790 // GLES 3.1 spec: 12.1. TRANSFORM FEEDBACK
3791 // The error INVALID_OPERATION is generated by BeginTransformFeedback if any binding point used
3792 // in transform feedback mode does not have a buffer object bound.
3793 glBeginTransformFeedback(GL_TRIANGLES);
3794 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3795 }
3796
3797 // Test that transform feedback query works when render pass is started while transform feedback is
3798 // paused.
TEST_P(TransformFeedbackTest,TransformFeedbackQueryPausedDrawThenResume)3799 TEST_P(TransformFeedbackTest, TransformFeedbackQueryPausedDrawThenResume)
3800 {
3801 constexpr char kVS[] = R"(
3802 attribute vec4 pos;
3803 varying vec4 v;
3804
3805 void main()
3806 {
3807 v = vec4(0.25, 0.5, 0.75, 1.0);
3808 gl_Position = pos;
3809 })";
3810
3811 constexpr char kFS[] = R"(
3812 precision mediump float;
3813 varying vec4 v;
3814 void main()
3815 {
3816 gl_FragColor = v;
3817 })";
3818
3819 const std::vector<std::string> tfVaryings = {"v"};
3820 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
3821 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
3822
3823 const GLfloat vertices[] = {
3824 -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
3825 };
3826 GLint positionLocation = glGetAttribLocation(program, "pos");
3827 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
3828 glEnableVertexAttribArray(positionLocation);
3829
3830 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
3831 glClearDepthf(0.1f);
3832 glClearStencil(0x5A);
3833 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3834
3835 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
3836
3837 // Test the following:
3838 //
3839 // - Start xfb and query
3840 // - Draw
3841 // - Pause query
3842 // - break the render pass
3843 //
3844 // - Draw without xfb, starts a new render pass
3845 // - Without breaking the render pass, resume xfb
3846 // - Draw with xfb
3847 // - End query and xfb
3848 //
3849 // The test ensures that the query is made active on resume.
3850
3851 glUseProgram(program);
3852 glBeginTransformFeedback(GL_POINTS);
3853 EXPECT_GL_NO_ERROR();
3854
3855 GLQuery xfbQuery;
3856 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, xfbQuery);
3857 EXPECT_GL_NO_ERROR();
3858
3859 // Draw with xfb.
3860 glDrawArrays(GL_POINTS, 0, 3);
3861
3862 glPauseTransformFeedback();
3863
3864 // Issue a copy to make sure the render pass is broken.
3865 GLTexture copyTex;
3866 glBindTexture(GL_TEXTURE_2D, copyTex);
3867 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
3868
3869 // Start a render pass without xfb.
3870 glUseProgram(drawRed);
3871 glDrawArrays(GL_POINTS, 0, 3);
3872
3873 // Resume xfb and issue another draw call.
3874 glUseProgram(program);
3875 glResumeTransformFeedback();
3876 glDrawArrays(GL_POINTS, 0, 3);
3877
3878 // End the query and verify results.
3879 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
3880 glEndTransformFeedback();
3881
3882 GLuint primitivesWritten = 0;
3883 glGetQueryObjectuiv(xfbQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
3884 EXPECT_GL_NO_ERROR();
3885
3886 EXPECT_EQ(primitivesWritten, 6u);
3887
3888 void *mappedBuffer = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
3889 sizeof(float) * 4 * 3 * 2, GL_MAP_READ_BIT);
3890 ASSERT_NE(nullptr, mappedBuffer);
3891
3892 float *mappedFloats = static_cast<float *>(mappedBuffer);
3893 for (unsigned int cnt = 0; cnt < 6; ++cnt)
3894 {
3895 EXPECT_NEAR(mappedFloats[4 * cnt + 0], 0.25f, 0.01f) << cnt;
3896 EXPECT_NEAR(mappedFloats[4 * cnt + 1], 0.5f, 0.01f) << cnt;
3897 EXPECT_NEAR(mappedFloats[4 * cnt + 2], 0.75f, 0.01f) << cnt;
3898 EXPECT_NEAR(mappedFloats[4 * cnt + 3], 1.0f, 0.01f) << cnt;
3899 }
3900 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3901
3902 EXPECT_GL_NO_ERROR();
3903 }
3904
3905 //angle CVE-2022-0975
3906 // Tests that we don't produce undefined behaviour when deleting a current XFB buffer.
TEST_P(TransformFeedbackTest,DeleteTransformFeedbackBuffer)3907 TEST_P(TransformFeedbackTest, DeleteTransformFeedbackBuffer)
3908 {
3909 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(testProgram, essl1_shaders::vs::Simple(),
3910 essl1_shaders::fs::Green(), {"gl_Position"},
3911 GL_INTERLEAVED_ATTRIBS);
3912 glUseProgram(testProgram);
3913
3914 GLBuffer buf;
3915 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buf);
3916 std::vector<uint8_t> bufData(100000, 0);
3917 glBufferData(GL_PIXEL_UNPACK_BUFFER, bufData.size(), bufData.data(), GL_DYNAMIC_COPY);
3918 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
3919 glBeginTransformFeedback(GL_POINTS);
3920 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3921 buf.reset();
3922 glDrawArrays(GL_POINTS, 0, 1);
3923 }
3924
3925 //angle CVE-2022-1477
3926 // Tests that deleting a buffer then resuming transform feedback produces an error.
TEST_P(TransformFeedbackTest,ResumingTransformFeedbackAfterDeletebuffer)3927 TEST_P(TransformFeedbackTest, ResumingTransformFeedbackAfterDeletebuffer)
3928 {
3929 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(testProgram, essl1_shaders::vs::Simple(),
3930 essl1_shaders::fs::Green(), {"gl_Position"},
3931 GL_INTERLEAVED_ATTRIBS);
3932 glUseProgram(testProgram);
3933
3934 std::vector<uint8_t> bufData(100, 0);
3935
3936 GLBuffer buf;
3937 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buf);
3938 glBufferData(GL_PIXEL_UNPACK_BUFFER, bufData.size(), bufData.data(), GL_DYNAMIC_COPY);
3939 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf);
3940 glBeginTransformFeedback(GL_POINTS);
3941 glPauseTransformFeedback();
3942 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3943 buf.reset();
3944 ASSERT_GL_NO_ERROR();
3945
3946 // Should produce an error because of a missing buffer binding.
3947 glResumeTransformFeedback();
3948 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3949 }
3950
3951 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest);
3952 ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest);
3953
3954 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackLifetimeTest);
3955 ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackLifetimeTest);
3956
3957 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTestES31);
3958 ANGLE_INSTANTIATE_TEST_ES31(TransformFeedbackTestES31);
3959
3960 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTestIOBlocks);
3961 ANGLE_INSTANTIATE_TEST_ES31(TransformFeedbackTestIOBlocks);
3962
3963 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTestES32);
3964 ANGLE_INSTANTIATE_TEST_ES32(TransformFeedbackTestES32);
3965
3966 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackWithDepthBufferTest);
3967 ANGLE_INSTANTIATE_TEST(TransformFeedbackWithDepthBufferTest, ES3_METAL());
3968 } // anonymous namespace
3969