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