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