xref: /aosp_15_r20/external/angle/src/tests/gl_tests/TransformFeedbackTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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, &currentBufferBinding);
866     EXPECT_EQ(static_cast<GLuint>(currentBufferBinding), mTransformFeedbackBuffer);
867 
868     glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &currentBufferBinding);
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, &currentBufferBinding);
877     EXPECT_EQ(0, currentBufferBinding);
878 
879     // But the generic bind point is unaffected by glBindTransformFeedback.
880     glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &currentBufferBinding);
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, &currentBufferBinding);
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, &currentBufferBinding);
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