xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ProgramPipelineTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2017 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 // ProgramPipelineTest:
7 //   Various tests related to Program Pipeline.
8 //
9 
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12 
13 using namespace angle;
14 
15 namespace
16 {
17 
18 class ProgramPipelineTest : public ANGLETest<>
19 {
20   protected:
ProgramPipelineTest()21     ProgramPipelineTest()
22     {
23         setWindowWidth(64);
24         setWindowHeight(64);
25         setConfigRedBits(8);
26         setConfigGreenBits(8);
27         setConfigBlueBits(8);
28         setConfigAlphaBits(8);
29     }
30 };
31 
32 // Verify that program pipeline is not supported in version lower than ES31.
TEST_P(ProgramPipelineTest,GenerateProgramPipelineObject)33 TEST_P(ProgramPipelineTest, GenerateProgramPipelineObject)
34 {
35     ANGLE_SKIP_TEST_IF(!IsVulkan());
36 
37     GLuint pipeline;
38     glGenProgramPipelines(1, &pipeline);
39     if (getClientMajorVersion() < 3 || getClientMinorVersion() < 1)
40     {
41         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
42     }
43     else
44     {
45         EXPECT_GL_NO_ERROR();
46 
47         glDeleteProgramPipelines(1, &pipeline);
48         EXPECT_GL_NO_ERROR();
49     }
50 }
51 
52 // Verify that program pipeline errors out without GL_EXT_separate_shader_objects extension.
TEST_P(ProgramPipelineTest,GenerateProgramPipelineObjectEXT)53 TEST_P(ProgramPipelineTest, GenerateProgramPipelineObjectEXT)
54 {
55     GLuint pipeline;
56     glGenProgramPipelinesEXT(1, &pipeline);
57     if (!IsGLExtensionEnabled("GL_EXT_separate_shader_objects"))
58     {
59         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
60     }
61     else
62     {
63         EXPECT_GL_NO_ERROR();
64 
65         glDeleteProgramPipelinesEXT(1, &pipeline);
66         EXPECT_GL_NO_ERROR();
67     }
68 }
69 
70 class ProgramPipelineTest31 : public ProgramPipelineTest
71 {
72   protected:
testTearDown()73     void testTearDown() override
74     {
75         glDeleteProgram(mVertProg);
76         glDeleteProgram(mFragProg);
77         glDeleteProgramPipelines(1, &mPipeline);
78     }
79 
80     void bindProgramPipeline(const GLchar *vertString, const GLchar *fragString);
81     void drawQuadWithPPO(const std::string &positionAttribName,
82                          const GLfloat positionAttribZ,
83                          const GLfloat positionAttribXYScale);
84     GLint getAvailableProgramBinaryFormatCount() const;
85 
86     GLuint mVertProg = 0;
87     GLuint mFragProg = 0;
88     GLuint mPipeline = 0;
89 };
90 
91 class ProgramPipelineXFBTest31 : public ProgramPipelineTest31
92 {
93   protected:
testSetUp()94     void testSetUp() override
95     {
96         glGenBuffers(1, &mTransformFeedbackBuffer);
97         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
98         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, nullptr,
99                      GL_STATIC_DRAW);
100 
101         glGenTransformFeedbacks(1, &mTransformFeedback);
102 
103         ASSERT_GL_NO_ERROR();
104     }
testTearDown()105     void testTearDown() override
106     {
107         if (mTransformFeedbackBuffer != 0)
108         {
109             glDeleteBuffers(1, &mTransformFeedbackBuffer);
110             mTransformFeedbackBuffer = 0;
111         }
112 
113         if (mTransformFeedback != 0)
114         {
115             glDeleteTransformFeedbacks(1, &mTransformFeedback);
116             mTransformFeedback = 0;
117         }
118     }
119 
120     void bindProgramPipelineWithXFBVaryings(const GLchar *vertString,
121                                             const GLchar *fragStringconst,
122                                             const std::vector<std::string> &tfVaryings,
123                                             GLenum bufferMode);
124 
125     static const size_t mTransformFeedbackBufferSize = 1 << 24;
126     GLuint mTransformFeedbackBuffer;
127     GLuint mTransformFeedback;
128 };
129 
bindProgramPipeline(const GLchar * vertString,const GLchar * fragString)130 void ProgramPipelineTest31::bindProgramPipeline(const GLchar *vertString, const GLchar *fragString)
131 {
132     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
133     ASSERT_NE(mVertProg, 0u);
134     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
135     ASSERT_NE(mFragProg, 0u);
136 
137     // Generate a program pipeline and attach the programs to their respective stages
138     glGenProgramPipelines(1, &mPipeline);
139     EXPECT_GL_NO_ERROR();
140     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
141     EXPECT_GL_NO_ERROR();
142     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
143     EXPECT_GL_NO_ERROR();
144     glBindProgramPipeline(mPipeline);
145     EXPECT_GL_NO_ERROR();
146 }
147 
bindProgramPipelineWithXFBVaryings(const GLchar * vertString,const GLchar * fragString,const std::vector<std::string> & tfVaryings,GLenum bufferMode)148 void ProgramPipelineXFBTest31::bindProgramPipelineWithXFBVaryings(
149     const GLchar *vertString,
150     const GLchar *fragString,
151     const std::vector<std::string> &tfVaryings,
152     GLenum bufferMode)
153 {
154     GLShader vertShader(GL_VERTEX_SHADER);
155     mVertProg = glCreateProgram();
156 
157     glShaderSource(vertShader, 1, &vertString, nullptr);
158     glCompileShader(vertShader);
159     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
160     glAttachShader(mVertProg, vertShader);
161     glLinkProgram(mVertProg);
162     EXPECT_GL_NO_ERROR();
163 
164     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
165     ASSERT_NE(mFragProg, 0u);
166 
167     if (tfVaryings.size() > 0)
168     {
169         std::vector<const char *> constCharTFVaryings;
170 
171         for (const std::string &transformFeedbackVarying : tfVaryings)
172         {
173             constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
174         }
175 
176         glTransformFeedbackVaryings(mVertProg, static_cast<GLsizei>(tfVaryings.size()),
177                                     &constCharTFVaryings[0], bufferMode);
178         glLinkProgram(mVertProg);
179     }
180     // Generate a program pipeline and attach the programs to their respective stages
181     glGenProgramPipelines(1, &mPipeline);
182     EXPECT_GL_NO_ERROR();
183     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
184     EXPECT_GL_NO_ERROR();
185     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
186     EXPECT_GL_NO_ERROR();
187     glBindProgramPipeline(mPipeline);
188     EXPECT_GL_NO_ERROR();
189 }
190 
191 // Test generate or delete program pipeline.
TEST_P(ProgramPipelineTest31,GenOrDeleteProgramPipelineTest)192 TEST_P(ProgramPipelineTest31, GenOrDeleteProgramPipelineTest)
193 {
194     ANGLE_SKIP_TEST_IF(!IsVulkan());
195 
196     GLuint pipeline;
197     glGenProgramPipelines(-1, &pipeline);
198     EXPECT_GL_ERROR(GL_INVALID_VALUE);
199     glGenProgramPipelines(0, &pipeline);
200     EXPECT_GL_NO_ERROR();
201 
202     glDeleteProgramPipelines(-1, &pipeline);
203     EXPECT_GL_ERROR(GL_INVALID_VALUE);
204     glDeleteProgramPipelines(0, &pipeline);
205     EXPECT_GL_NO_ERROR();
206 }
207 
208 // Test BindProgramPipeline.
TEST_P(ProgramPipelineTest31,BindProgramPipelineTest)209 TEST_P(ProgramPipelineTest31, BindProgramPipelineTest)
210 {
211     ANGLE_SKIP_TEST_IF(!IsVulkan());
212 
213     glBindProgramPipeline(0);
214     EXPECT_GL_NO_ERROR();
215 
216     glBindProgramPipeline(2);
217     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
218 
219     GLuint pipeline;
220     glGenProgramPipelines(1, &pipeline);
221     glBindProgramPipeline(pipeline);
222     EXPECT_GL_NO_ERROR();
223 
224     glDeleteProgramPipelines(1, &pipeline);
225     glBindProgramPipeline(pipeline);
226     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
227 }
228 
229 // Test IsProgramPipeline
TEST_P(ProgramPipelineTest31,IsProgramPipelineTest)230 TEST_P(ProgramPipelineTest31, IsProgramPipelineTest)
231 {
232     ANGLE_SKIP_TEST_IF(!IsVulkan());
233 
234     EXPECT_GL_FALSE(glIsProgramPipeline(0));
235     EXPECT_GL_NO_ERROR();
236 
237     EXPECT_GL_FALSE(glIsProgramPipeline(2));
238     EXPECT_GL_NO_ERROR();
239 
240     GLuint pipeline;
241     glGenProgramPipelines(1, &pipeline);
242     glBindProgramPipeline(pipeline);
243     EXPECT_GL_TRUE(glIsProgramPipeline(pipeline));
244     EXPECT_GL_NO_ERROR();
245 
246     glBindProgramPipeline(0);
247     glDeleteProgramPipelines(1, &pipeline);
248     EXPECT_GL_FALSE(glIsProgramPipeline(pipeline));
249     EXPECT_GL_NO_ERROR();
250 }
251 
252 // Simulates a call to glCreateShaderProgramv()
createShaderProgram(GLenum type,const GLchar * shaderString,unsigned int varyingsCount,const char * const * varyings)253 GLuint createShaderProgram(GLenum type,
254                            const GLchar *shaderString,
255                            unsigned int varyingsCount,
256                            const char *const *varyings)
257 {
258     GLShader shader(type);
259     if (!shader)
260     {
261         return 0;
262     }
263 
264     glShaderSource(shader, 1, &shaderString, nullptr);
265     EXPECT_GL_NO_ERROR();
266 
267     glCompileShader(shader);
268 
269     GLint compiled;
270     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
271 
272     if (!compiled)
273     {
274         GLint infoLogLength;
275         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
276         std::vector<GLchar> infoLog(infoLogLength);
277         glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog.data());
278         INFO() << "Compilation failed:\n"
279                << (infoLogLength > 0 ? infoLog.data() : "") << "\n for shader:\n"
280                << shaderString << "\n";
281         return 0;
282     }
283 
284     GLuint program = glCreateProgram();
285 
286     if (program)
287     {
288         glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
289         if (compiled)
290         {
291             glAttachShader(program, shader);
292             EXPECT_GL_NO_ERROR();
293 
294             if (varyingsCount > 0)
295             {
296                 glTransformFeedbackVaryings(program, varyingsCount, varyings, GL_SEPARATE_ATTRIBS);
297                 EXPECT_GL_NO_ERROR();
298             }
299 
300             glLinkProgram(program);
301 
302             GLint linked = 0;
303             glGetProgramiv(program, GL_LINK_STATUS, &linked);
304 
305             if (linked == 0)
306             {
307                 glDeleteProgram(program);
308                 return 0;
309             }
310             glDetachShader(program, shader);
311         }
312     }
313 
314     EXPECT_GL_NO_ERROR();
315 
316     return program;
317 }
318 
createShaderProgram(GLenum type,const GLchar * shaderString)319 GLuint createShaderProgram(GLenum type, const GLchar *shaderString)
320 {
321     return createShaderProgram(type, shaderString, 0, nullptr);
322 }
323 
drawQuadWithPPO(const std::string & positionAttribName,const GLfloat positionAttribZ,const GLfloat positionAttribXYScale)324 void ProgramPipelineTest31::drawQuadWithPPO(const std::string &positionAttribName,
325                                             const GLfloat positionAttribZ,
326                                             const GLfloat positionAttribXYScale)
327 {
328     return drawQuadPPO(mVertProg, positionAttribName, positionAttribZ, positionAttribXYScale);
329 }
330 
getAvailableProgramBinaryFormatCount() const331 GLint ProgramPipelineTest31::getAvailableProgramBinaryFormatCount() const
332 {
333     GLint formatCount = 0;
334     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
335     return formatCount;
336 }
337 
338 // Test glUseProgramStages
TEST_P(ProgramPipelineTest31,UseProgramStages)339 TEST_P(ProgramPipelineTest31, UseProgramStages)
340 {
341     ANGLE_SKIP_TEST_IF(!IsVulkan());
342 
343     // Create two separable program objects from a
344     // single source string respectively (vertSrc and fragSrc)
345     const GLchar *vertString = essl31_shaders::vs::Simple();
346     const GLchar *fragString = essl31_shaders::fs::Red();
347 
348     mVertProg = createShaderProgram(GL_VERTEX_SHADER, vertString);
349     ASSERT_NE(mVertProg, 0u);
350     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, fragString);
351     ASSERT_NE(mFragProg, 0u);
352 
353     // Generate a program pipeline and attach the programs to their respective stages
354     GLuint pipeline;
355     glGenProgramPipelines(1, &pipeline);
356     EXPECT_GL_NO_ERROR();
357     glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, mVertProg);
358     EXPECT_GL_NO_ERROR();
359     glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
360     EXPECT_GL_NO_ERROR();
361     glBindProgramPipeline(pipeline);
362     EXPECT_GL_NO_ERROR();
363 
364     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
365     ASSERT_GL_NO_ERROR();
366     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
367 }
368 
369 // Test glUseProgramStages with different programs
TEST_P(ProgramPipelineTest31,UseProgramStagesWithDifferentPrograms)370 TEST_P(ProgramPipelineTest31, UseProgramStagesWithDifferentPrograms)
371 {
372     ANGLE_SKIP_TEST_IF(!IsVulkan());
373 
374     // Create two separable program objects from a
375     // single source string respectively (vertSrc and fragSrc)
376     const GLchar *vertString  = essl31_shaders::vs::Simple();
377     const GLchar *fragString1 = R"(#version 310 es
378 precision highp float;
379 uniform float redColorIn;
380 uniform float greenColorIn;
381 out vec4 my_FragColor;
382 void main()
383 {
384     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
385 })";
386     const GLchar *fragString2 = R"(#version 310 es
387 precision highp float;
388 uniform float greenColorIn;
389 uniform float blueColorIn;
390 out vec4 my_FragColor;
391 void main()
392 {
393     my_FragColor = vec4(0.0, greenColorIn, blueColorIn, 1.0);
394 })";
395 
396     bindProgramPipeline(vertString, fragString1);
397 
398     // Set the output color to red
399     GLint location = glGetUniformLocation(mFragProg, "redColorIn");
400     glActiveShaderProgram(mPipeline, mFragProg);
401     glUniform1f(location, 1.0);
402     location = glGetUniformLocation(mFragProg, "greenColorIn");
403     glActiveShaderProgram(mPipeline, mFragProg);
404     glUniform1f(location, 0.0);
405 
406     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
407     ASSERT_GL_NO_ERROR();
408     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
409 
410     GLuint fragProg;
411     fragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString2);
412     ASSERT_NE(fragProg, 0u);
413     EXPECT_GL_NO_ERROR();
414 
415     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, fragProg);
416     EXPECT_GL_NO_ERROR();
417 
418     glClearColor(0.0, 0.0, 0.0, 0.0);
419     glClear(GL_COLOR_BUFFER_BIT);
420 
421     // Set the output color to blue
422     location = glGetUniformLocation(fragProg, "greenColorIn");
423     glActiveShaderProgram(mPipeline, fragProg);
424     glUniform1f(location, 0.0);
425     location = glGetUniformLocation(fragProg, "blueColorIn");
426     glActiveShaderProgram(mPipeline, fragProg);
427     glUniform1f(location, 1.0);
428 
429     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
430     ASSERT_GL_NO_ERROR();
431     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
432 
433     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
434     EXPECT_GL_NO_ERROR();
435 
436     glClearColor(0.0, 0.0, 0.0, 0.0);
437     glClear(GL_COLOR_BUFFER_BIT);
438 
439     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
440     ASSERT_GL_NO_ERROR();
441     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
442 
443     glDeleteProgram(mVertProg);
444     glDeleteProgram(mFragProg);
445     glDeleteProgram(fragProg);
446 }
447 
448 // Test glUseProgramStages
TEST_P(ProgramPipelineTest31,UseCreateShaderProgramv)449 TEST_P(ProgramPipelineTest31, UseCreateShaderProgramv)
450 {
451     ANGLE_SKIP_TEST_IF(!IsVulkan());
452 
453     // Create two separable program objects from a
454     // single source string respectively (vertSrc and fragSrc)
455     const GLchar *vertString = essl31_shaders::vs::Simple();
456     const GLchar *fragString = essl31_shaders::fs::Red();
457 
458     bindProgramPipeline(vertString, fragString);
459 
460     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
461     ASSERT_GL_NO_ERROR();
462     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
463 }
464 
465 // Test pipeline without vertex shader
TEST_P(ProgramPipelineTest31,PipelineWithoutVertexShader)466 TEST_P(ProgramPipelineTest31, PipelineWithoutVertexShader)
467 {
468     ANGLE_SKIP_TEST_IF(!IsVulkan());
469 
470     // Create a separable program object with a fragment shader
471     const GLchar *fragString = essl31_shaders::fs::Red();
472     mFragProg                = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
473     ASSERT_NE(mFragProg, 0u);
474 
475     // Generate a program pipeline and attach the program to it's respective stage
476     glGenProgramPipelines(1, &mPipeline);
477     EXPECT_GL_NO_ERROR();
478     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
479     EXPECT_GL_NO_ERROR();
480     glBindProgramPipeline(mPipeline);
481     EXPECT_GL_NO_ERROR();
482 
483     glDrawArrays(GL_POINTS, 0, 3);
484     ASSERT_GL_NO_ERROR();
485 }
486 
487 // Test pipeline without any shaders
TEST_P(ProgramPipelineTest31,PipelineWithoutShaders)488 TEST_P(ProgramPipelineTest31, PipelineWithoutShaders)
489 {
490     ANGLE_SKIP_TEST_IF(!IsVulkan());
491 
492     // Generate a program pipeline
493     glGenProgramPipelines(1, &mPipeline);
494     EXPECT_GL_NO_ERROR();
495 
496     glBindProgramPipeline(mPipeline);
497     EXPECT_GL_NO_ERROR();
498 
499     glDrawArrays(GL_POINTS, 0, 3);
500     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
501 
502     // Ensure validation fails
503     GLint value;
504     glValidateProgramPipeline(mPipeline);
505     glGetProgramPipelineiv(mPipeline, GL_VALIDATE_STATUS, &value);
506     EXPECT_FALSE(value);
507 }
508 
509 // Test glUniform
TEST_P(ProgramPipelineTest31,FragmentStageUniformTest)510 TEST_P(ProgramPipelineTest31, FragmentStageUniformTest)
511 {
512     ANGLE_SKIP_TEST_IF(!IsVulkan());
513 
514     // Create two separable program objects from a
515     // single source string respectively (vertSrc and fragSrc)
516     const GLchar *vertString = essl31_shaders::vs::Simple();
517     const GLchar *fragString = R"(#version 310 es
518 precision highp float;
519 uniform float redColorIn;
520 uniform float greenColorIn;
521 out vec4 my_FragColor;
522 void main()
523 {
524     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
525 })";
526 
527     bindProgramPipeline(vertString, fragString);
528 
529     // Set the output color to yellow
530     GLint location = glGetUniformLocation(mFragProg, "redColorIn");
531     glActiveShaderProgram(mPipeline, mFragProg);
532     glUniform1f(location, 1.0);
533     location = glGetUniformLocation(mFragProg, "greenColorIn");
534     glActiveShaderProgram(mPipeline, mFragProg);
535     glUniform1f(location, 1.0);
536 
537     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
538     ASSERT_GL_NO_ERROR();
539     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
540 
541     glClearColor(0.0, 0.0, 0.0, 0.0);
542     glClear(GL_COLOR_BUFFER_BIT);
543 
544     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
545     ASSERT_GL_NO_ERROR();
546     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
547 
548     glClearColor(0.0, 0.0, 0.0, 0.0);
549     glClear(GL_COLOR_BUFFER_BIT);
550 
551     // Set the output color to red
552     location = glGetUniformLocation(mFragProg, "redColorIn");
553     glActiveShaderProgram(mPipeline, mFragProg);
554     glUniform1f(location, 1.0);
555     location = glGetUniformLocation(mFragProg, "greenColorIn");
556     glActiveShaderProgram(mPipeline, mFragProg);
557     glUniform1f(location, 0.0);
558 
559     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
560     ASSERT_GL_NO_ERROR();
561     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
562 
563     glDeleteProgram(mVertProg);
564     glDeleteProgram(mFragProg);
565 }
566 
567 // Test glUniformBlockBinding and then glBufferData
TEST_P(ProgramPipelineTest31,FragmentStageUniformBlockBufferDataTest)568 TEST_P(ProgramPipelineTest31, FragmentStageUniformBlockBufferDataTest)
569 {
570     ANGLE_SKIP_TEST_IF(!IsVulkan());
571 
572     // Create two separable program objects from a
573     // single source string respectively (vertSrc and fragSrc)
574     const GLchar *vertString = essl31_shaders::vs::Simple();
575     const GLchar *fragString = R"(#version 310 es
576 precision highp float;
577 layout (std140) uniform color_ubo
578 {
579     float redColorIn;
580     float greenColorIn;
581 };
582 
583 out vec4 my_FragColor;
584 void main()
585 {
586     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
587 })";
588 
589     bindProgramPipeline(vertString, fragString);
590 
591     // Set the output color to yellow
592     glActiveShaderProgram(mPipeline, mFragProg);
593     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
594     GLBuffer uboBuf;
595     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf);
596     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
597     glUniformBlockBinding(mFragProg, uboIndex, 0);
598     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
599     ASSERT_GL_NO_ERROR();
600     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
601 
602     // Clear and test again
603     glClearColor(0.0, 0.0, 0.0, 0.0);
604     glClear(GL_COLOR_BUFFER_BIT);
605     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
606     // Set the output color to red
607     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
608     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf);
609     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
610     ASSERT_GL_NO_ERROR();
611     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
612 
613     glDeleteProgram(mVertProg);
614     glDeleteProgram(mFragProg);
615 }
616 
617 // Test glUniformBlockBinding followed by glBindBufferRange
TEST_P(ProgramPipelineTest31,FragmentStageUniformBlockBindBufferRangeTest)618 TEST_P(ProgramPipelineTest31, FragmentStageUniformBlockBindBufferRangeTest)
619 {
620     ANGLE_SKIP_TEST_IF(!IsVulkan());
621 
622     // Create two separable program objects from a
623     // single source string respectively (vertSrc and fragSrc)
624     const GLchar *vertString = essl31_shaders::vs::Simple();
625     const GLchar *fragString = R"(#version 310 es
626 precision highp float;
627 layout (std140) uniform color_ubo
628 {
629     float redColorIn;
630     float greenColorIn;
631     float blueColorIn;
632 };
633 
634 out vec4 my_FragColor;
635 void main()
636 {
637     my_FragColor = vec4(redColorIn, greenColorIn, blueColorIn, 1.0);
638 })";
639 
640     // Setup three uniform buffers, one with red, one with green, and one with blue
641     GLBuffer uboBufRed;
642     glBindBuffer(GL_UNIFORM_BUFFER, uboBufRed);
643     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
644     GLBuffer uboBufGreen;
645     glBindBuffer(GL_UNIFORM_BUFFER, uboBufGreen);
646     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
647     GLBuffer uboBufBlue;
648     glBindBuffer(GL_UNIFORM_BUFFER, uboBufBlue);
649     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatBlue, GL_STATIC_DRAW);
650 
651     // Setup pipeline program using red uniform buffer
652     bindProgramPipeline(vertString, fragString);
653     glActiveShaderProgram(mPipeline, mFragProg);
654     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
655     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufRed);
656     glUniformBlockBinding(mFragProg, uboIndex, 0);
657     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
658     ASSERT_GL_NO_ERROR();
659     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
660 
661     // Clear and test again
662     glClearColor(0.0, 0.0, 0.0, 0.0);
663     glClear(GL_COLOR_BUFFER_BIT);
664     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
665     // bind to green uniform buffer
666     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufGreen);
667     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
668     // bind to blue uniform buffer
669     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufBlue);
670     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
671     ASSERT_GL_NO_ERROR();
672     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
673 
674     glDeleteProgram(mVertProg);
675     glDeleteProgram(mFragProg);
676 }
677 
678 // Test that glUniformBlockBinding can successfully change the binding for PPOs
TEST_P(ProgramPipelineTest31,FragmentStageUniformBlockBinding)679 TEST_P(ProgramPipelineTest31, FragmentStageUniformBlockBinding)
680 {
681     ANGLE_SKIP_TEST_IF(!IsVulkan());
682 
683     // Create two separable program objects from a
684     // single source string respectively (vertSrc and fragSrc)
685     const GLchar *vertString = essl31_shaders::vs::Simple();
686     const GLchar *fragString = R"(#version 310 es
687 precision highp float;
688 layout (std140) uniform color_ubo
689 {
690     float redColorIn;
691     float greenColorIn;
692     float blueColorIn;
693 };
694 
695 out vec4 my_FragColor;
696 void main()
697 {
698     my_FragColor = vec4(redColorIn, greenColorIn, blueColorIn, 1.0);
699 })";
700 
701     // Setup three uniform buffers, one with red, one with green, and one with blue
702     GLBuffer uboBufRed;
703     glBindBuffer(GL_UNIFORM_BUFFER, uboBufRed);
704     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
705     GLBuffer uboBufGreen;
706     glBindBuffer(GL_UNIFORM_BUFFER, uboBufGreen);
707     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
708     GLBuffer uboBufBlue;
709     glBindBuffer(GL_UNIFORM_BUFFER, uboBufBlue);
710     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatBlue, GL_STATIC_DRAW);
711 
712     // Setup pipeline program using red uniform buffer
713     bindProgramPipeline(vertString, fragString);
714     glActiveShaderProgram(mPipeline, mFragProg);
715     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
716 
717     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufRed);
718     glBindBufferBase(GL_UNIFORM_BUFFER, 1, uboBufGreen);
719     glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboBufBlue);
720 
721     // Bind the UBO to binding 0 and draw, should be red
722     const int w = getWindowWidth();
723     const int h = getWindowHeight();
724     glEnable(GL_SCISSOR_TEST);
725     glScissor(0, 0, w / 2, h / 2);
726     glUniformBlockBinding(mFragProg, uboIndex, 0);
727     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
728 
729     // Bind it to binding 1 and draw, should be green
730     glScissor(w / 2, 0, w - w / 2, h / 2);
731     glUniformBlockBinding(mFragProg, uboIndex, 1);
732     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
733 
734     // Bind it to binding 2 and draw, should be blue
735     glScissor(0, h / 2, w, h);
736     glUniformBlockBinding(mFragProg, uboIndex, 2);
737     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
738 
739     EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h / 2, GLColor::red);
740     EXPECT_PIXEL_RECT_EQ(w / 2, 0, w - w / 2, h / 2, GLColor::green);
741     EXPECT_PIXEL_RECT_EQ(0, h / 2, w, h - h / 2, GLColor::blue);
742     ASSERT_GL_NO_ERROR();
743 }
744 
745 // Test that dirty bits related to UBOs propagates to the PPO.
TEST_P(ProgramPipelineTest31,UniformBufferUpdatesBeforeBindToPPO)746 TEST_P(ProgramPipelineTest31, UniformBufferUpdatesBeforeBindToPPO)
747 {
748     ANGLE_SKIP_TEST_IF(!IsVulkan());
749 
750     const GLchar *vertString = essl31_shaders::vs::Simple();
751     const GLchar *fragString = R"(#version 310 es
752 precision highp float;
753 layout (std140) uniform color_ubo
754 {
755     float redColorIn;
756     float greenColorIn;
757     float blueColorIn;
758 };
759 
760 out vec4 my_FragColor;
761 void main()
762 {
763     my_FragColor = vec4(redColorIn, greenColorIn, blueColorIn, 1.0);
764 })";
765 
766     GLuint vs = CompileShader(GL_VERTEX_SHADER, vertString);
767     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragString);
768     mVertProg = glCreateProgram();
769     mFragProg = glCreateProgram();
770 
771     // Compile and link a separable vertex shader
772     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
773     glAttachShader(mVertProg, vs);
774     glLinkProgram(mVertProg);
775     EXPECT_GL_NO_ERROR();
776 
777     // Compile and link a separable fragment shader
778     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
779     glAttachShader(mFragProg, fs);
780     glLinkProgram(mFragProg);
781     EXPECT_GL_NO_ERROR();
782 
783     // Generate a program pipeline and attach the programs
784     glGenProgramPipelines(1, &mPipeline);
785     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
786     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
787     glBindProgramPipeline(mPipeline);
788     EXPECT_GL_NO_ERROR();
789 
790     GLBuffer uboBufRed;
791     glBindBuffer(GL_UNIFORM_BUFFER, uboBufRed);
792     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
793     GLBuffer uboBufGreen;
794     glBindBuffer(GL_UNIFORM_BUFFER, uboBufGreen);
795     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
796     GLBuffer uboBufBlue;
797     glBindBuffer(GL_UNIFORM_BUFFER, uboBufBlue);
798     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatBlue, GL_STATIC_DRAW);
799 
800     glActiveShaderProgram(mPipeline, mFragProg);
801     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
802     glUniformBlockBinding(mFragProg, uboIndex, 0);
803     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufRed);
804     glBindBufferBase(GL_UNIFORM_BUFFER, 1, uboBufGreen);
805 
806     // Draw once so all dirty bits are handled.  Should be red
807     const int w = getWindowWidth();
808     const int h = getWindowHeight();
809     glEnable(GL_SCISSOR_TEST);
810     glScissor(0, 0, w / 2, h / 2);
811     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
812 
813     // Unbind the fragment program from the PPO
814     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, 0);
815     EXPECT_GL_NO_ERROR();
816 
817     // Modify the UBO bindings, reattach the program and draw again.  Should be green
818     glUniformBlockBinding(mFragProg, uboIndex, 1);
819 
820     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
821     glScissor(w / 2, 0, w - w / 2, h / 2);
822     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
823 
824     // Unbind the fragment program from the PPO again, and modify the UBO bindings differently.
825     // Draw again, which should be blue.
826     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, 0);
827     glBindBufferBase(GL_UNIFORM_BUFFER, 1, uboBufBlue);
828 
829     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
830     glScissor(0, h / 2, w, h);
831     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
832 
833     EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h / 2, GLColor::red);
834     EXPECT_PIXEL_RECT_EQ(w / 2, 0, w - w / 2, h / 2, GLColor::green);
835     EXPECT_PIXEL_RECT_EQ(0, h / 2, w, h - h / 2, GLColor::blue);
836     ASSERT_GL_NO_ERROR();
837 }
838 
839 // Test glBindBufferRange between draw calls in the presence of multiple UBOs between VS and FS
TEST_P(ProgramPipelineTest31,BindBufferRangeForMultipleUBOsInMultipleStages)840 TEST_P(ProgramPipelineTest31, BindBufferRangeForMultipleUBOsInMultipleStages)
841 {
842     ANGLE_SKIP_TEST_IF(!IsVulkan());
843 
844     // Create two separable program objects from a
845     // single source string respectively (vertSrc and fragSrc)
846     const GLchar *vertString = R"(#version 310 es
847 precision highp float;
848 layout (std140) uniform vsUBO1
849 {
850     float redIn;
851 };
852 
853 layout (std140) uniform vsUBO2
854 {
855     float greenIn;
856 };
857 
858 out float red;
859 out float green;
860 
861 void main()
862 {
863     vec2 pos = vec2(0.0);
864     switch (gl_VertexID) {
865         case 0: pos = vec2(-1.0, -1.0); break;
866         case 1: pos = vec2(3.0, -1.0); break;
867         case 2: pos = vec2(-1.0, 3.0); break;
868     };
869     gl_Position = vec4(pos, 0.0, 1.0);
870     red = redIn;
871     green = greenIn;
872 })";
873     const GLchar *fragString = R"(#version 310 es
874 precision highp float;
875 layout (std140) uniform fsUBO1
876 {
877     float blueIn;
878 };
879 
880 layout (std140) uniform fsUBO2
881 {
882     float alphaIn;
883 };
884 
885 in float red;
886 in float green;
887 
888 out vec4 my_FragColor;
889 void main()
890 {
891     my_FragColor = vec4(red, green, blueIn, alphaIn);
892 })";
893 
894     // Setup two uniform buffers, one with 1, one with 0
895     GLBuffer ubo0;
896     glBindBuffer(GL_UNIFORM_BUFFER, ubo0);
897     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatBlack, GL_STATIC_DRAW);
898     GLBuffer ubo1;
899     glBindBuffer(GL_UNIFORM_BUFFER, ubo1);
900     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
901 
902     bindProgramPipeline(vertString, fragString);
903 
904     // Setup the initial bindings to draw red
905     const GLint vsUBO1 = glGetUniformBlockIndex(mVertProg, "vsUBO1");
906     const GLint vsUBO2 = glGetUniformBlockIndex(mVertProg, "vsUBO2");
907     const GLint fsUBO1 = glGetUniformBlockIndex(mFragProg, "fsUBO1");
908     const GLint fsUBO2 = glGetUniformBlockIndex(mFragProg, "fsUBO2");
909     glUniformBlockBinding(mVertProg, vsUBO1, 0);
910     glUniformBlockBinding(mVertProg, vsUBO2, 1);
911     glUniformBlockBinding(mFragProg, fsUBO1, 2);
912     glUniformBlockBinding(mFragProg, fsUBO2, 3);
913 
914     glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo1);
915     glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo0);
916     glBindBufferBase(GL_UNIFORM_BUFFER, 2, ubo0);
917     glBindBufferBase(GL_UNIFORM_BUFFER, 3, ubo1);
918 
919     const int w = getWindowWidth();
920     const int h = getWindowHeight();
921     glEnable(GL_SCISSOR_TEST);
922     glScissor(0, 0, w / 2, h / 2);
923 
924     glDrawArrays(GL_TRIANGLES, 0, 3);
925 
926     // Change the bindings in the vertex shader UBO binding and draw again, should be yellow.
927     glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo1);
928     glScissor(w / 2, 0, w - w / 2, h / 2);
929     glDrawArrays(GL_TRIANGLES, 0, 3);
930 
931     // Change the bindings in the fragment shader UBO binding and draw again, should be white.
932     glBindBufferBase(GL_UNIFORM_BUFFER, 2, ubo1);
933     glScissor(0, h / 2, w / 2, h - h / 2);
934     glDrawArrays(GL_TRIANGLES, 0, 3);
935 
936     // Change the bindings in both shader UBO bindings and draw again, should be green.
937     glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo0);
938     glBindBufferBase(GL_UNIFORM_BUFFER, 2, ubo0);
939     glScissor(w / 2, h / 2, w - w / 2, h - h / 2);
940     glDrawArrays(GL_TRIANGLES, 0, 3);
941     ASSERT_GL_NO_ERROR();
942 
943     EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h / 2, GLColor::red);
944     EXPECT_PIXEL_RECT_EQ(w / 2, 0, w - w / 2, h / 2, GLColor::yellow);
945     EXPECT_PIXEL_RECT_EQ(0, h / 2, w / 2, h - h / 2, GLColor::white);
946     EXPECT_PIXEL_RECT_EQ(w / 2, h / 2, w - w / 2, h - h / 2, GLColor::green);
947     ASSERT_GL_NO_ERROR();
948 }
949 
950 // Test varyings
TEST_P(ProgramPipelineTest31,ProgramPipelineVaryings)951 TEST_P(ProgramPipelineTest31, ProgramPipelineVaryings)
952 {
953     ANGLE_SKIP_TEST_IF(!IsVulkan());
954 
955     // Create two separable program objects from a
956     // single source string respectively (vertSrc and fragSrc)
957     const GLchar *vertString = essl31_shaders::vs::Passthrough();
958     const GLchar *fragString = R"(#version 310 es
959 precision highp float;
960 in vec4 v_position;
961 out vec4 my_FragColor;
962 void main()
963 {
964     my_FragColor = round(v_position);
965 })";
966 
967     bindProgramPipeline(vertString, fragString);
968 
969     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
970     ASSERT_GL_NO_ERROR();
971 
972     int w = getWindowWidth() - 2;
973     int h = getWindowHeight() - 2;
974 
975     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
976     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::red);
977     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::green);
978     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
979 }
980 
981 // Creates a program pipeline with a 2D texture and renders with it.
TEST_P(ProgramPipelineTest31,DrawWith2DTexture)982 TEST_P(ProgramPipelineTest31, DrawWith2DTexture)
983 {
984     ANGLE_SKIP_TEST_IF(!IsVulkan());
985 
986     const GLchar *vertString = R"(#version 310 es
987 precision highp float;
988 in vec4 a_position;
989 out vec2 texCoord;
990 void main()
991 {
992     gl_Position = a_position;
993     texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
994 })";
995 
996     const GLchar *fragString = R"(#version 310 es
997 precision highp float;
998 in vec2 texCoord;
999 uniform sampler2D tex;
1000 out vec4 my_FragColor;
1001 void main()
1002 {
1003     my_FragColor = texture(tex, texCoord);
1004 })";
1005 
1006     std::array<GLColor, 4> colors = {
1007         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
1008 
1009     GLTexture tex;
1010     glBindTexture(GL_TEXTURE_2D, tex);
1011     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
1012     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1013     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1014 
1015     bindProgramPipeline(vertString, fragString);
1016 
1017     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1018     ASSERT_GL_NO_ERROR();
1019 
1020     int w = getWindowWidth() - 2;
1021     int h = getWindowHeight() - 2;
1022 
1023     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1024     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
1025     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
1026     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
1027 }
1028 
1029 // Test modifying a shader after it has been detached from a pipeline
TEST_P(ProgramPipelineTest31,DetachAndModifyShader)1030 TEST_P(ProgramPipelineTest31, DetachAndModifyShader)
1031 {
1032     ANGLE_SKIP_TEST_IF(!IsVulkan());
1033 
1034     const GLchar *vertString = essl31_shaders::vs::Simple();
1035     const GLchar *fragString = essl31_shaders::fs::Green();
1036 
1037     GLShader vertShader(GL_VERTEX_SHADER);
1038     GLShader fragShader(GL_FRAGMENT_SHADER);
1039     mVertProg = glCreateProgram();
1040     mFragProg = glCreateProgram();
1041 
1042     // Compile and link a separable vertex shader
1043     glShaderSource(vertShader, 1, &vertString, nullptr);
1044     glCompileShader(vertShader);
1045     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1046     glAttachShader(mVertProg, vertShader);
1047     glLinkProgram(mVertProg);
1048     EXPECT_GL_NO_ERROR();
1049 
1050     // Compile and link a separable fragment shader
1051     glShaderSource(fragShader, 1, &fragString, nullptr);
1052     glCompileShader(fragShader);
1053     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1054     glAttachShader(mFragProg, fragShader);
1055     glLinkProgram(mFragProg);
1056     EXPECT_GL_NO_ERROR();
1057 
1058     // Generate a program pipeline and attach the programs
1059     glGenProgramPipelines(1, &mPipeline);
1060     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1061     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1062     glBindProgramPipeline(mPipeline);
1063     EXPECT_GL_NO_ERROR();
1064 
1065     // Draw once to ensure this worked fine
1066     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1067     ASSERT_GL_NO_ERROR();
1068     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1069 
1070     // Detach the fragment shader and modify it such that it no longer fits with this pipeline
1071     glDetachShader(mFragProg, fragShader);
1072 
1073     // Add an input to the fragment shader, which will make it incompatible
1074     const GLchar *fragString2 = R"(#version 310 es
1075 precision highp float;
1076 in vec4 color;
1077 out vec4 my_FragColor;
1078 void main()
1079 {
1080     my_FragColor = color;
1081 })";
1082     glShaderSource(fragShader, 1, &fragString2, nullptr);
1083     glCompileShader(fragShader);
1084 
1085     // Link and draw with the program again, which should be fine since the shader was detached
1086     glLinkProgram(mFragProg);
1087 
1088     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1089     ASSERT_GL_NO_ERROR();
1090 }
1091 
1092 // Test binding two programs that use a texture as different types
TEST_P(ProgramPipelineTest31,DifferentTextureTypes)1093 TEST_P(ProgramPipelineTest31, DifferentTextureTypes)
1094 {
1095     // Only the Vulkan backend supports PPO
1096     ANGLE_SKIP_TEST_IF(!IsVulkan());
1097 
1098     // Per the OpenGL ES 3.1 spec:
1099     //
1100     // It is not allowed to have variables of different sampler types pointing to the same texture
1101     // image unit within a program object. This situation can only be detected at the next rendering
1102     // command issued which triggers shader invocations, and an INVALID_OPERATION error will then
1103     // be generated
1104     //
1105 
1106     // Create a vertex shader that uses the texture as 2D
1107     const GLchar *vertString = R"(#version 310 es
1108 precision highp float;
1109 in vec4 a_position;
1110 uniform sampler2D tex2D;
1111 layout(location = 0) out vec4 texColorOut;
1112 layout(location = 1) out vec2 texCoordOut;
1113 void main()
1114 {
1115     gl_Position = a_position;
1116     vec2 texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
1117     texColorOut = textureLod(tex2D, texCoord, 0.0);
1118     texCoordOut = texCoord;
1119 })";
1120 
1121     // Create a fragment shader that uses the texture as Cube
1122     const GLchar *fragString = R"(#version 310 es
1123 precision highp float;
1124 layout(location = 0) in vec4 texColor;
1125 layout(location = 1) in vec2 texCoord;
1126 uniform samplerCube texCube;
1127 out vec4 my_FragColor;
1128 void main()
1129 {
1130     my_FragColor = texture(texCube, vec3(texCoord.x, texCoord.y, 0.0));
1131 })";
1132 
1133     // Create and populate the 2D texture
1134     std::array<GLColor, 4> colors = {
1135         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
1136     GLTexture tex;
1137     glBindTexture(GL_TEXTURE_2D, tex);
1138     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
1139     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1140     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1141 
1142     // Create a pipeline that uses the bad combination.  This should fail to link the pipeline.
1143     bindProgramPipeline(vertString, fragString);
1144     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1145     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1146 
1147     // Update the fragment shader to correctly use 2D texture
1148     const GLchar *fragString2 = R"(#version 310 es
1149 precision highp float;
1150 layout(location = 0) in vec4 texColor;
1151 layout(location = 1) in vec2 texCoord;
1152 uniform sampler2D tex2D;
1153 out vec4 my_FragColor;
1154 void main()
1155 {
1156     my_FragColor = texture(tex2D, texCoord);
1157 })";
1158 
1159     // Bind the pipeline again, which should succeed.
1160     bindProgramPipeline(vertString, fragString2);
1161     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1162     ASSERT_GL_NO_ERROR();
1163 }
1164 
1165 // Tests that we receive a PPO link validation error when attempting to draw with the bad PPO
TEST_P(ProgramPipelineTest31,VerifyPpoLinkErrorSignalledCorrectly)1166 TEST_P(ProgramPipelineTest31, VerifyPpoLinkErrorSignalledCorrectly)
1167 {
1168     // Create pipeline that should fail link
1169     // Bind program
1170     // Draw
1171     // Unbind program
1172     // Draw  <<--- expect a link validation error here
1173 
1174     // Only the Vulkan backend supports PPOs
1175     ANGLE_SKIP_TEST_IF(!IsVulkan());
1176 
1177     // Create two separable program objects from a
1178     // single source string respectively (vertSrc and fragSrc)
1179     const GLchar *vertString = essl31_shaders::vs::Simple();
1180     const GLchar *fragString = essl31_shaders::fs::Red();
1181     // Create a fragment shader that takes a color input
1182     // This should cause the PPO link to fail, since the varyings don't match (no output from VS).
1183     const GLchar *fragStringBad = R"(#version 310 es
1184 precision highp float;
1185 layout(location = 0) in vec4 colorIn;
1186 out vec4 my_FragColor;
1187 void main()
1188 {
1189     my_FragColor = colorIn;
1190 })";
1191     bindProgramPipeline(vertString, fragStringBad);
1192 
1193     ANGLE_GL_PROGRAM(program, vertString, fragString);
1194     drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f, 1.0f, true);
1195     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1196 
1197     // Draw with the PPO, which should generate an error due to the link failure.
1198     glUseProgram(0);
1199     ASSERT_GL_NO_ERROR();
1200     drawQuadWithPPO(essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
1201     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1202 }
1203 
1204 // Tests creating two program pipelines with a common shader and a varying location mismatch.
TEST_P(ProgramPipelineTest31,VaryingLocationMismatch)1205 TEST_P(ProgramPipelineTest31, VaryingLocationMismatch)
1206 {
1207     // Only the Vulkan backend supports PPOs
1208     ANGLE_SKIP_TEST_IF(!IsVulkan());
1209 
1210     // Create a fragment shader using the varying location "5".
1211     const char *kFS = R"(#version 310 es
1212 precision mediump float;
1213 layout(location = 5) in vec4 color;
1214 out vec4 colorOut;
1215 void main()
1216 {
1217     colorOut = color;
1218 })";
1219 
1220     // Create a pipeline with a vertex shader using varying location "5". Should succeed.
1221     const char *kVSGood = R"(#version 310 es
1222 precision mediump float;
1223 layout(location = 5) out vec4 color;
1224 in vec4 position;
1225 uniform float uniOne;
1226 void main()
1227 {
1228     gl_Position = position;
1229     color = vec4(0, uniOne, 0, 1);
1230 })";
1231 
1232     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &kVSGood);
1233     ASSERT_NE(mVertProg, 0u);
1234     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &kFS);
1235     ASSERT_NE(mFragProg, 0u);
1236 
1237     // Generate a program pipeline and attach the programs to their respective stages
1238     glGenProgramPipelines(1, &mPipeline);
1239     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1240     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1241     glBindProgramPipeline(mPipeline);
1242     ASSERT_GL_NO_ERROR();
1243 
1244     GLint location = glGetUniformLocation(mVertProg, "uniOne");
1245     ASSERT_NE(-1, location);
1246     glActiveShaderProgram(mPipeline, mVertProg);
1247     glUniform1f(location, 1.0);
1248     ASSERT_GL_NO_ERROR();
1249 
1250     drawQuadWithPPO("position", 0.5f, 1.0f);
1251     ASSERT_GL_NO_ERROR();
1252 
1253     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1254 
1255     // Create a pipeline with a vertex shader using varying location "3". Should fail.
1256     const char *kVSBad = R"(#version 310 es
1257 precision mediump float;
1258 layout(location = 3) out vec4 color;
1259 in vec4 position;
1260 uniform float uniOne;
1261 void main()
1262 {
1263     gl_Position = position;
1264     color = vec4(0, uniOne, 0, 1);
1265 })";
1266 
1267     glDeleteProgram(mVertProg);
1268     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &kVSBad);
1269     ASSERT_NE(mVertProg, 0u);
1270 
1271     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1272     ASSERT_GL_NO_ERROR();
1273 
1274     drawQuadWithPPO("position", 0.5f, 1.0f);
1275     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1276 }
1277 
1278 // Test that uniform updates are propagated with minimal state changes.
TEST_P(ProgramPipelineTest31,UniformUpdate)1279 TEST_P(ProgramPipelineTest31, UniformUpdate)
1280 {
1281     ANGLE_SKIP_TEST_IF(!IsVulkan());
1282 
1283     // Create two separable program objects from a
1284     // single source string respectively (vertSrc and fragSrc)
1285     const GLchar *vertString = essl31_shaders::vs::Simple();
1286     const GLchar *fragString = R"(#version 310 es
1287 precision highp float;
1288 uniform float redColorIn;
1289 uniform float greenColorIn;
1290 out vec4 my_FragColor;
1291 void main()
1292 {
1293     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
1294 })";
1295 
1296     bindProgramPipeline(vertString, fragString);
1297 
1298     GLint redLoc = glGetUniformLocation(mFragProg, "redColorIn");
1299     ASSERT_NE(-1, redLoc);
1300     GLint greenLoc = glGetUniformLocation(mFragProg, "greenColorIn");
1301     ASSERT_NE(-1, greenLoc);
1302 
1303     glActiveShaderProgram(mPipeline, mFragProg);
1304 
1305     std::array<Vector3, 6> verts = GetQuadVertices();
1306 
1307     GLBuffer vbo;
1308     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1309     glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
1310 
1311     GLint posLoc = glGetAttribLocation(mVertProg, essl31_shaders::PositionAttrib());
1312     glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1313     glEnableVertexAttribArray(posLoc);
1314 
1315     glClearColor(0.0, 0.0, 0.0, 0.0);
1316     glClear(GL_COLOR_BUFFER_BIT);
1317 
1318     // Set the output color to red, draw to left half of window.
1319     glUniform1f(redLoc, 1.0);
1320     glUniform1f(greenLoc, 0.0);
1321     glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
1322     glDrawArrays(GL_TRIANGLES, 0, 6);
1323     ASSERT_GL_NO_ERROR();
1324 
1325     // Set the output color to green, draw to right half of window.
1326     glUniform1f(redLoc, 0.0);
1327     glUniform1f(greenLoc, 1.0);
1328 
1329     glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight());
1330     glDrawArrays(GL_TRIANGLES, 0, 6);
1331     ASSERT_GL_NO_ERROR();
1332 
1333     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1334     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 + 1, 0, GLColor::green);
1335 }
1336 
1337 // Test that uniform updates propagate to two pipelines.
TEST_P(ProgramPipelineTest31,UniformUpdateTwoPipelines)1338 TEST_P(ProgramPipelineTest31, UniformUpdateTwoPipelines)
1339 {
1340     ANGLE_SKIP_TEST_IF(!IsVulkan());
1341 
1342     // Create two separable program objects from a
1343     // single source string respectively (vertSrc and fragSrc)
1344     const GLchar *vertString = essl31_shaders::vs::Simple();
1345     const GLchar *fragString = R"(#version 310 es
1346 precision highp float;
1347 uniform float redColorIn;
1348 uniform float greenColorIn;
1349 out vec4 my_FragColor;
1350 void main()
1351 {
1352     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
1353 })";
1354 
1355     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
1356     ASSERT_NE(mVertProg, 0u);
1357     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
1358     ASSERT_NE(mFragProg, 0u);
1359 
1360     GLint redLoc = glGetUniformLocation(mFragProg, "redColorIn");
1361     ASSERT_NE(-1, redLoc);
1362     GLint greenLoc = glGetUniformLocation(mFragProg, "greenColorIn");
1363     ASSERT_NE(-1, greenLoc);
1364 
1365     GLProgramPipeline ppo1;
1366     glUseProgramStages(ppo1, GL_VERTEX_SHADER_BIT, mVertProg);
1367     glUseProgramStages(ppo1, GL_FRAGMENT_SHADER_BIT, mFragProg);
1368     glBindProgramPipeline(ppo1);
1369     glActiveShaderProgram(ppo1, mFragProg);
1370     ASSERT_GL_NO_ERROR();
1371 
1372     GLProgramPipeline ppo2;
1373     glUseProgramStages(ppo2, GL_VERTEX_SHADER_BIT, mVertProg);
1374     glUseProgramStages(ppo2, GL_FRAGMENT_SHADER_BIT, mFragProg);
1375     glBindProgramPipeline(ppo2);
1376     glActiveShaderProgram(ppo2, mFragProg);
1377     ASSERT_GL_NO_ERROR();
1378 
1379     std::array<Vector3, 6> verts = GetQuadVertices();
1380 
1381     GLBuffer vbo;
1382     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1383     glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
1384 
1385     GLint posLoc = glGetAttribLocation(mVertProg, essl31_shaders::PositionAttrib());
1386     glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1387     glEnableVertexAttribArray(posLoc);
1388 
1389     glClearColor(0.0, 0.0, 0.0, 0.0);
1390     glClear(GL_COLOR_BUFFER_BIT);
1391 
1392     const GLsizei w = getWindowWidth() / 2;
1393     const GLsizei h = getWindowHeight() / 2;
1394 
1395     // Set the output color to red, draw to UL quad of window with first PPO.
1396     glUniform1f(redLoc, 1.0);
1397     glUniform1f(greenLoc, 0.0);
1398     glBindProgramPipeline(ppo1);
1399     glViewport(0, 0, w, h);
1400     glDrawArrays(GL_TRIANGLES, 0, 6);
1401     ASSERT_GL_NO_ERROR();
1402 
1403     // Draw red to UR half of window with second PPO.
1404     glBindProgramPipeline(ppo2);
1405     glViewport(w, 0, w, h);
1406     glDrawArrays(GL_TRIANGLES, 0, 6);
1407     ASSERT_GL_NO_ERROR();
1408 
1409     // Draw green to LL corner of window with first PPO.
1410     glUniform1f(redLoc, 0.0);
1411     glUniform1f(greenLoc, 1.0);
1412     glBindProgramPipeline(ppo1);
1413     glViewport(0, h, w, h);
1414     glDrawArrays(GL_TRIANGLES, 0, 6);
1415     ASSERT_GL_NO_ERROR();
1416 
1417     // Draw green to LR half of window with second PPO.
1418     glBindProgramPipeline(ppo2);
1419     glViewport(w, h, w, h);
1420     glDrawArrays(GL_TRIANGLES, 0, 6);
1421     ASSERT_GL_NO_ERROR();
1422 
1423     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1424     EXPECT_PIXEL_COLOR_EQ(w + 1, 0, GLColor::red);
1425     EXPECT_PIXEL_COLOR_EQ(0, h + 1, GLColor::green);
1426     EXPECT_PIXEL_COLOR_EQ(w + 1, h + 1, GLColor::green);
1427 }
1428 
1429 // Tests that setting sampler bindings on a program before the pipeline works as expected.
TEST_P(ProgramPipelineTest31,BindSamplerBeforeCreatingPipeline)1430 TEST_P(ProgramPipelineTest31, BindSamplerBeforeCreatingPipeline)
1431 {
1432     ANGLE_SKIP_TEST_IF(!IsVulkan());
1433 
1434     // Create two textures - red and green.
1435     GLTexture redTex;
1436     glBindTexture(GL_TEXTURE_2D, redTex);
1437     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
1438     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1439     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1440 
1441     GLTexture greenTex;
1442     glBindTexture(GL_TEXTURE_2D, greenTex);
1443     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1444     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1445     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1446 
1447     // Bind red to texture unit 0 and green to unit 1.
1448     glActiveTexture(GL_TEXTURE0);
1449     glBindTexture(GL_TEXTURE_2D, redTex);
1450 
1451     glActiveTexture(GL_TEXTURE1);
1452     glBindTexture(GL_TEXTURE_2D, greenTex);
1453 
1454     // Create the separable programs.
1455     const char *vsSource = essl1_shaders::vs::Texture2D();
1456     mVertProg            = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vsSource);
1457     ASSERT_NE(0u, mVertProg);
1458 
1459     const char *fsSource = essl1_shaders::fs::Texture2D();
1460     mFragProg            = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fsSource);
1461     ASSERT_NE(0u, mFragProg);
1462 
1463     // Set the program to sample from the green texture.
1464     GLint texLoc = glGetUniformLocation(mFragProg, essl1_shaders::Texture2DUniform());
1465     ASSERT_NE(-1, texLoc);
1466 
1467     glUseProgram(mFragProg);
1468     glUniform1i(texLoc, 1);
1469 
1470     ASSERT_GL_NO_ERROR();
1471 
1472     // Create and draw with the pipeline.
1473     GLProgramPipeline ppo;
1474     glUseProgramStages(ppo, GL_VERTEX_SHADER_BIT, mVertProg);
1475     glUseProgramStages(ppo, GL_FRAGMENT_SHADER_BIT, mFragProg);
1476     glBindProgramPipeline(ppo);
1477 
1478     ASSERT_GL_NO_ERROR();
1479 
1480     drawQuadWithPPO(essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
1481     ASSERT_GL_NO_ERROR();
1482 
1483     // We should have sampled from the second texture bound to unit 1.
1484     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1485 }
1486 
1487 // Test that a shader IO block varying with separable program links
1488 // successfully.
TEST_P(ProgramPipelineTest31,VaryingIOBlockSeparableProgram)1489 TEST_P(ProgramPipelineTest31, VaryingIOBlockSeparableProgram)
1490 {
1491     // Only the Vulkan backend supports PPOs
1492     ANGLE_SKIP_TEST_IF(!IsVulkan());
1493     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
1494 
1495     constexpr char kVS[] =
1496         R"(#version 310 es
1497         #extension GL_EXT_shader_io_blocks : require
1498 
1499         precision highp float;
1500         in vec4 inputAttribute;
1501         out Block_inout { vec4 value; } user_out;
1502 
1503         void main()
1504         {
1505             gl_Position    = inputAttribute;
1506             user_out.value = vec4(4.0, 5.0, 6.0, 7.0);
1507         })";
1508 
1509     constexpr char kFS[] =
1510         R"(#version 310 es
1511         #extension GL_EXT_shader_io_blocks : require
1512 
1513         precision highp float;
1514         layout(location = 0) out mediump vec4 color;
1515         in Block_inout { vec4 value; } user_in;
1516 
1517         void main()
1518         {
1519             color = vec4(1, 0, 0, 1);
1520         })";
1521 
1522     bindProgramPipeline(kVS, kFS);
1523     drawQuadWithPPO("inputAttribute", 0.5f, 1.0f);
1524     ASSERT_GL_NO_ERROR();
1525     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1526 }
1527 
1528 // Test that a shader IO block varying with separable program links
1529 // successfully.
TEST_P(ProgramPipelineXFBTest31,VaryingIOBlockSeparableProgramWithXFB)1530 TEST_P(ProgramPipelineXFBTest31, VaryingIOBlockSeparableProgramWithXFB)
1531 {
1532     // Only the Vulkan backend supports PPOs
1533     ANGLE_SKIP_TEST_IF(!IsVulkan());
1534     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
1535 
1536     constexpr char kVS[] =
1537         R"(#version 310 es
1538         #extension GL_EXT_shader_io_blocks : require
1539 
1540         precision highp float;
1541         in vec4 inputAttribute;
1542         out Block_inout { vec4 value; vec4 value2; } user_out;
1543 
1544         void main()
1545         {
1546             gl_Position    = inputAttribute;
1547             user_out.value = vec4(4.0, 5.0, 6.0, 7.0);
1548             user_out.value2 = vec4(8.0, 9.0, 10.0, 11.0);
1549         })";
1550 
1551     constexpr char kFS[] =
1552         R"(#version 310 es
1553         #extension GL_EXT_shader_io_blocks : require
1554 
1555         precision highp float;
1556         layout(location = 0) out mediump vec4 color;
1557         in Block_inout { vec4 value; vec4 value2; } user_in;
1558 
1559         void main()
1560         {
1561             color = vec4(1, 0, 0, 1);
1562         })";
1563     std::vector<std::string> tfVaryings;
1564     tfVaryings.push_back("Block_inout.value");
1565     tfVaryings.push_back("Block_inout.value2");
1566     bindProgramPipelineWithXFBVaryings(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1567     glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1568 
1569     // Make sure reconfiguring the vertex shader's transform feedback varyings without a link does
1570     // not affect the pipeline.  Same with changing buffer modes
1571     std::vector<const char *> tfVaryingsBogus = {"some", "invalid[0]", "names"};
1572     glTransformFeedbackVaryings(mVertProg, static_cast<GLsizei>(tfVaryingsBogus.size()),
1573                                 tfVaryingsBogus.data(), GL_SEPARATE_ATTRIBS);
1574 
1575     glBeginTransformFeedback(GL_TRIANGLES);
1576     drawQuadWithPPO("inputAttribute", 0.5f, 1.0f);
1577     glEndTransformFeedback();
1578 
1579     ASSERT_GL_NO_ERROR();
1580     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1581 
1582     void *mappedBuffer =
1583         glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 8, GL_MAP_READ_BIT);
1584     ASSERT_NE(nullptr, mappedBuffer);
1585 
1586     float *mappedFloats = static_cast<float *>(mappedBuffer);
1587     for (unsigned int cnt = 0; cnt < 8; ++cnt)
1588     {
1589         EXPECT_EQ(4 + cnt, mappedFloats[cnt]);
1590     }
1591     glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1592 
1593     EXPECT_GL_NO_ERROR();
1594 }
1595 
1596 // Test modifying a shader and re-linking it updates the PPO too
TEST_P(ProgramPipelineTest31,ModifyAndRelinkShader)1597 TEST_P(ProgramPipelineTest31, ModifyAndRelinkShader)
1598 {
1599     ANGLE_SKIP_TEST_IF(!IsVulkan());
1600 
1601     const GLchar *vertString      = essl31_shaders::vs::Simple();
1602     const GLchar *fragStringGreen = essl31_shaders::fs::Green();
1603     const GLchar *fragStringRed   = essl31_shaders::fs::Red();
1604 
1605     GLShader vertShader(GL_VERTEX_SHADER);
1606     GLShader fragShader(GL_FRAGMENT_SHADER);
1607     mVertProg = glCreateProgram();
1608     mFragProg = glCreateProgram();
1609 
1610     // Compile and link a separable vertex shader
1611     glShaderSource(vertShader, 1, &vertString, nullptr);
1612     glCompileShader(vertShader);
1613     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1614     glAttachShader(mVertProg, vertShader);
1615     glLinkProgram(mVertProg);
1616     EXPECT_GL_NO_ERROR();
1617 
1618     // Compile and link a separable fragment shader
1619     glShaderSource(fragShader, 1, &fragStringGreen, nullptr);
1620     glCompileShader(fragShader);
1621     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1622     glAttachShader(mFragProg, fragShader);
1623     glLinkProgram(mFragProg);
1624     EXPECT_GL_NO_ERROR();
1625 
1626     // Generate a program pipeline and attach the programs
1627     glGenProgramPipelines(1, &mPipeline);
1628     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1629     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1630     glBindProgramPipeline(mPipeline);
1631     EXPECT_GL_NO_ERROR();
1632 
1633     // Draw once to ensure this worked fine
1634     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1635     ASSERT_GL_NO_ERROR();
1636     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1637 
1638     // Detach the fragment shader and modify it such that it no longer fits with this pipeline
1639     glDetachShader(mFragProg, fragShader);
1640 
1641     // Modify the FS and re-link it
1642     glShaderSource(fragShader, 1, &fragStringRed, nullptr);
1643     glCompileShader(fragShader);
1644     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1645     glAttachShader(mFragProg, fragShader);
1646     glLinkProgram(mFragProg);
1647     EXPECT_GL_NO_ERROR();
1648 
1649     // Draw with the PPO again and verify it's now red
1650     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1651     ASSERT_GL_NO_ERROR();
1652     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1653 }
1654 
1655 // Test that a PPO can be used when the attached shader programs are created with glProgramBinary().
1656 // This validates the necessary programs' information is serialized/deserialized so they can be
1657 // linked by the PPO during glDrawArrays.
TEST_P(ProgramPipelineTest31,ProgramBinary)1658 TEST_P(ProgramPipelineTest31, ProgramBinary)
1659 {
1660     ANGLE_SKIP_TEST_IF(!IsVulkan());
1661     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1662 
1663     const GLchar *vertString = R"(#version 310 es
1664 precision highp float;
1665 in vec4 a_position;
1666 out vec2 texCoord;
1667 void main()
1668 {
1669     gl_Position = a_position;
1670     texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
1671 })";
1672 
1673     const GLchar *fragString = R"(#version 310 es
1674 precision highp float;
1675 in vec2 texCoord;
1676 uniform sampler2D tex;
1677 out vec4 my_FragColor;
1678 void main()
1679 {
1680     my_FragColor = texture(tex, texCoord);
1681 })";
1682 
1683     std::array<GLColor, 4> colors = {
1684         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
1685 
1686     GLTexture tex;
1687     glBindTexture(GL_TEXTURE_2D, tex);
1688     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
1689     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1690     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1691 
1692     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
1693     ASSERT_NE(mVertProg, 0u);
1694     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
1695     ASSERT_NE(mFragProg, 0u);
1696 
1697     // Save the VS program binary out
1698     std::vector<uint8_t> vsBinary(0);
1699     GLint vsProgramLength = 0;
1700     GLint vsWrittenLength = 0;
1701     GLenum vsBinaryFormat = 0;
1702     glGetProgramiv(mVertProg, GL_PROGRAM_BINARY_LENGTH, &vsProgramLength);
1703     ASSERT_GL_NO_ERROR();
1704     vsBinary.resize(vsProgramLength);
1705     glGetProgramBinary(mVertProg, vsProgramLength, &vsWrittenLength, &vsBinaryFormat,
1706                        vsBinary.data());
1707     ASSERT_GL_NO_ERROR();
1708 
1709     // Save the FS program binary out
1710     std::vector<uint8_t> fsBinary(0);
1711     GLint fsProgramLength = 0;
1712     GLint fsWrittenLength = 0;
1713     GLenum fsBinaryFormat = 0;
1714     glGetProgramiv(mFragProg, GL_PROGRAM_BINARY_LENGTH, &fsProgramLength);
1715     ASSERT_GL_NO_ERROR();
1716     fsBinary.resize(fsProgramLength);
1717     glGetProgramBinary(mFragProg, fsProgramLength, &fsWrittenLength, &fsBinaryFormat,
1718                        fsBinary.data());
1719     ASSERT_GL_NO_ERROR();
1720 
1721     mVertProg = glCreateProgram();
1722     glProgramBinary(mVertProg, vsBinaryFormat, vsBinary.data(), vsWrittenLength);
1723     mFragProg = glCreateProgram();
1724     glProgramBinary(mFragProg, fsBinaryFormat, fsBinary.data(), fsWrittenLength);
1725 
1726     // Generate a program pipeline and attach the programs to their respective stages
1727     glGenProgramPipelines(1, &mPipeline);
1728     EXPECT_GL_NO_ERROR();
1729     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1730     EXPECT_GL_NO_ERROR();
1731     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1732     EXPECT_GL_NO_ERROR();
1733     glBindProgramPipeline(mPipeline);
1734     EXPECT_GL_NO_ERROR();
1735 
1736     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1737     ASSERT_GL_NO_ERROR();
1738 
1739     int w = getWindowWidth() - 2;
1740     int h = getWindowHeight() - 2;
1741 
1742     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1743     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
1744     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
1745     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
1746 }
1747 
1748 // Test that updating a sampler uniform in a separable program behaves correctly with PPOs.
TEST_P(ProgramPipelineTest31,SampleTextureAThenTextureB)1749 TEST_P(ProgramPipelineTest31, SampleTextureAThenTextureB)
1750 {
1751     ANGLE_SKIP_TEST_IF(!IsVulkan());
1752 
1753     constexpr int kWidth  = 2;
1754     constexpr int kHeight = 2;
1755 
1756     const GLchar *vertString = R"(#version 310 es
1757 precision highp float;
1758 in vec2 a_position;
1759 out vec2 texCoord;
1760 void main()
1761 {
1762     gl_Position = vec4(a_position, 0, 1);
1763     texCoord = a_position * 0.5 + vec2(0.5);
1764 })";
1765 
1766     const GLchar *fragString = R"(#version 310 es
1767 precision highp float;
1768 in vec2 texCoord;
1769 uniform sampler2D tex;
1770 out vec4 my_FragColor;
1771 void main()
1772 {
1773     my_FragColor = texture(tex, texCoord);
1774 })";
1775 
1776     std::array<GLColor, kWidth * kHeight> redColor = {
1777         {GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
1778     std::array<GLColor, kWidth * kHeight> greenColor = {
1779         {GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
1780 
1781     // Create a red texture and bind to texture unit 0
1782     GLTexture redTex;
1783     glActiveTexture(GL_TEXTURE0);
1784     glBindTexture(GL_TEXTURE_2D, redTex);
1785     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1786                  redColor.data());
1787     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1788     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1789     ASSERT_GL_NO_ERROR();
1790     // Create a green texture and bind to texture unit 1
1791     GLTexture greenTex;
1792     glActiveTexture(GL_TEXTURE1);
1793     glBindTexture(GL_TEXTURE_2D, greenTex);
1794     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1795                  greenColor.data());
1796     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1797     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1798     glActiveTexture(GL_TEXTURE0);
1799     ASSERT_GL_NO_ERROR();
1800 
1801     bindProgramPipeline(vertString, fragString);
1802 
1803     GLint location1 = glGetUniformLocation(mFragProg, "tex");
1804     ASSERT_NE(location1, -1);
1805     glActiveShaderProgram(mPipeline, mFragProg);
1806     ASSERT_GL_NO_ERROR();
1807 
1808     glEnable(GL_BLEND);
1809     glBlendEquation(GL_FUNC_ADD);
1810     glBlendFunc(GL_ONE, GL_ONE);
1811 
1812     // Draw red
1813     glUniform1i(location1, 0);
1814     ASSERT_GL_NO_ERROR();
1815     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1816     ASSERT_GL_NO_ERROR();
1817 
1818     // Draw green
1819     glUniform1i(location1, 1);
1820     ASSERT_GL_NO_ERROR();
1821     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1822     ASSERT_GL_NO_ERROR();
1823 
1824     EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::yellow);
1825 }
1826 
1827 // Verify that image uniforms can be used with separable programs
TEST_P(ProgramPipelineTest31,ImageUniforms)1828 TEST_P(ProgramPipelineTest31, ImageUniforms)
1829 {
1830     ANGLE_SKIP_TEST_IF(!IsVulkan());
1831 
1832     GLint maxVertexImageUniforms;
1833     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
1834     ANGLE_SKIP_TEST_IF(maxVertexImageUniforms == 0);
1835 
1836     const GLchar *vertString = R"(#version 310 es
1837 precision highp float;
1838 precision highp image2D;
1839 layout(binding = 0, r32f) uniform image2D img;
1840 
1841 void main()
1842 {
1843     gl_Position = imageLoad(img, ivec2(0, 0));
1844 })";
1845 
1846     const GLchar *fragString = essl31_shaders::fs::Red();
1847 
1848     bindProgramPipeline(vertString, fragString);
1849 
1850     GLTexture texture;
1851     GLfloat value = 1.0;
1852 
1853     glBindTexture(GL_TEXTURE_2D, texture);
1854     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 1, 1);
1855     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED, GL_FLOAT, &value);
1856     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1857     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1858 
1859     glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1860 
1861     glDrawArrays(GL_POINTS, 0, 6);
1862     ASSERT_GL_NO_ERROR();
1863 }
1864 
1865 // Verify that image uniforms can link in separable programs
TEST_P(ProgramPipelineTest31,LinkedImageUniforms)1866 TEST_P(ProgramPipelineTest31, LinkedImageUniforms)
1867 {
1868     ANGLE_SKIP_TEST_IF(!IsVulkan());
1869 
1870     GLint maxVertexImageUniforms;
1871     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
1872     ANGLE_SKIP_TEST_IF(maxVertexImageUniforms == 0);
1873 
1874     const GLchar *vertString = R"(#version 310 es
1875 precision highp float;
1876 precision highp image2D;
1877 layout(binding = 0, r32f) uniform image2D img;
1878 
1879 void main()
1880 {
1881     vec2 position = -imageLoad(img, ivec2(0, 0)).rr;
1882     if (gl_VertexID == 1)
1883         position = vec2(3, -1);
1884     else if (gl_VertexID == 2)
1885         position = vec2(-1, 3);
1886 
1887     gl_Position = vec4(position, 0, 1);
1888 })";
1889 
1890     const GLchar *fragString = R"(#version 310 es
1891 precision highp float;
1892 precision highp image2D;
1893 layout(binding = 0, r32f) uniform image2D img;
1894 layout(location = 0) out vec4 color;
1895 
1896 void main()
1897 {
1898     color = imageLoad(img, ivec2(0, 0));
1899 })";
1900 
1901     bindProgramPipeline(vertString, fragString);
1902 
1903     GLTexture texture;
1904     GLfloat value = 1.0;
1905 
1906     glBindTexture(GL_TEXTURE_2D, texture);
1907     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 1, 1);
1908     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED, GL_FLOAT, &value);
1909     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1910     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1911 
1912     glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1913 
1914     glDrawArrays(GL_TRIANGLES, 0, 3);
1915 
1916     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1917     ASSERT_GL_NO_ERROR();
1918 }
1919 
1920 // Verify that we can have the max amount of uniform buffer objects as part of a program
1921 // pipeline.
TEST_P(ProgramPipelineTest31,MaxFragmentUniformBufferObjects)1922 TEST_P(ProgramPipelineTest31, MaxFragmentUniformBufferObjects)
1923 {
1924     ANGLE_SKIP_TEST_IF(!IsVulkan());
1925 
1926     GLint maxUniformBlocks;
1927     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &maxUniformBlocks);
1928 
1929     const GLchar *vertString = essl31_shaders::vs::Simple();
1930     std::stringstream fragStringStream;
1931     fragStringStream << R"(#version 310 es
1932 precision highp float;
1933 out vec4 my_FragColor;
1934 layout(binding = 0) uniform block {
1935     float data;
1936 } ubo[)";
1937     fragStringStream << maxUniformBlocks;
1938     fragStringStream << R"(];
1939 void main()
1940 {
1941     my_FragColor = vec4(1.0);
1942 )";
1943     for (GLint index = 0; index < maxUniformBlocks; index++)
1944     {
1945         fragStringStream << "my_FragColor.x + ubo[" << index << "].data;" << std::endl;
1946     }
1947     fragStringStream << "}" << std::endl;
1948 
1949     bindProgramPipeline(vertString, fragStringStream.str().c_str());
1950 
1951     std::vector<GLBuffer> buffers(maxUniformBlocks);
1952     for (GLint index = 0; index < maxUniformBlocks; ++index)
1953     {
1954         glBindBuffer(GL_UNIFORM_BUFFER, buffers[index]);
1955         glBufferData(GL_UNIFORM_BUFFER, sizeof(GLfloat), NULL, GL_STATIC_DRAW);
1956         glBindBufferBase(GL_UNIFORM_BUFFER, index, buffers[index]);
1957     }
1958 
1959     glDrawArrays(GL_POINTS, 0, 6);
1960     ASSERT_GL_NO_ERROR();
1961 }
1962 
1963 // Verify that we can have the max amount of shader storage buffer objects as part of a program
1964 // pipeline.
TEST_P(ProgramPipelineTest31,MaxFragmentShaderStorageBufferObjects)1965 TEST_P(ProgramPipelineTest31, MaxFragmentShaderStorageBufferObjects)
1966 {
1967     ANGLE_SKIP_TEST_IF(!IsVulkan());
1968 
1969     GLint maxShaderStorageBuffers;
1970     glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxShaderStorageBuffers);
1971     const GLchar *vertString = essl31_shaders::vs::Simple();
1972     std::stringstream fragStringStream;
1973     fragStringStream << R"(#version 310 es
1974 precision highp float;
1975 out vec4 my_FragColor;
1976 layout(binding = 0) buffer buf {
1977     float data;
1978 } ssbo[)";
1979     fragStringStream << maxShaderStorageBuffers;
1980     fragStringStream << R"(];
1981 void main()
1982 {
1983     my_FragColor = vec4(1.0);
1984 )";
1985     for (GLint index = 0; index < maxShaderStorageBuffers; index++)
1986     {
1987         fragStringStream << "my_FragColor.x + ssbo[" << index << "].data;" << std::endl;
1988     }
1989     fragStringStream << "}" << std::endl;
1990 
1991     bindProgramPipeline(vertString, fragStringStream.str().c_str());
1992 
1993     std::vector<GLBuffer> buffers(maxShaderStorageBuffers);
1994     for (GLint index = 0; index < maxShaderStorageBuffers; ++index)
1995     {
1996         glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[index]);
1997         glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), NULL, GL_STATIC_DRAW);
1998         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, buffers[index]);
1999     }
2000 
2001     glDrawArrays(GL_POINTS, 0, 6);
2002     ASSERT_GL_NO_ERROR();
2003 }
2004 
2005 // Test validation of redefinition of gl_Position and gl_PointSize in the vertex shader when
2006 // GL_EXT_separate_shader_objects is enabled.
TEST_P(ProgramPipelineTest31,ValidatePositionPointSizeRedefinition)2007 TEST_P(ProgramPipelineTest31, ValidatePositionPointSizeRedefinition)
2008 {
2009     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_separate_shader_objects"));
2010 
2011     {
2012         constexpr char kVS[] = R"(#version 310 es
2013 #extension GL_EXT_separate_shader_objects: require
2014 
2015 out float gl_PointSize;
2016 
2017 void main()
2018 {
2019     gl_Position = vec4(0);
2020     gl_PointSize = 1.;
2021 })";
2022 
2023         // Should fail because gl_Position is not declared.
2024         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
2025         EXPECT_EQ(shader, 0u);
2026     }
2027 
2028     {
2029         constexpr char kVS[] = R"(#version 310 es
2030 #extension GL_EXT_separate_shader_objects: require
2031 
2032 out float gl_PointSize;
2033 
2034 void f()
2035 {
2036     gl_PointSize = 1.;
2037 }
2038 
2039 out vec4 gl_Position;
2040 
2041 void main()
2042 {
2043     gl_Position = vec4(0);
2044 })";
2045 
2046         // Should fail because gl_PointSize is used before gl_Position is declared.
2047         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
2048         EXPECT_EQ(shader, 0u);
2049     }
2050 
2051     {
2052         constexpr char kVS[] = R"(#version 310 es
2053 #extension GL_EXT_separate_shader_objects: require
2054 
2055 out float gl_PointSize;
2056 out vec4 gl_Position;
2057 
2058 void main()
2059 {
2060     gl_Position = vec4(0);
2061     gl_PointSize = 1.;
2062 })";
2063 
2064         // Should compile.
2065         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
2066         EXPECT_NE(shader, 0u);
2067     }
2068 }
2069 
2070 // Basic draw test with GL_EXT_separate_shader_objects enabled in the vertex shader
TEST_P(ProgramPipelineTest31,BasicDrawWithPositionPointSizeRedefinition)2071 TEST_P(ProgramPipelineTest31, BasicDrawWithPositionPointSizeRedefinition)
2072 {
2073     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_separate_shader_objects"));
2074 
2075     const char kVS[] = R"(#version 310 es
2076 #extension GL_EXT_separate_shader_objects: require
2077 
2078 out float gl_PointSize;
2079 out vec4 gl_Position;
2080 
2081 in vec4 a_position;
2082 
2083 void main()
2084 {
2085     gl_Position = a_position;
2086 })";
2087 
2088     mVertProg = createShaderProgram(GL_VERTEX_SHADER, kVS);
2089     ASSERT_NE(mVertProg, 0u);
2090     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, essl31_shaders::fs::Red());
2091     ASSERT_NE(mFragProg, 0u);
2092 
2093     // Generate a program pipeline and attach the programs to their respective stages
2094     GLuint pipeline;
2095     glGenProgramPipelines(1, &pipeline);
2096     glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, mVertProg);
2097     glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
2098     glBindProgramPipeline(pipeline);
2099     EXPECT_GL_NO_ERROR();
2100 
2101     drawQuadWithPPO("a_position", 0.5f, 1.0f);
2102     ASSERT_GL_NO_ERROR();
2103     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2104 }
2105 
2106 // Test a PPO scenario from a game, calling glBindBufferRange between two draws with
2107 // multiple binding points, some unused.  This would result in a crash without the fix.
2108 // https://issuetracker.google.com/issues/299532942
TEST_P(ProgramPipelineTest31,ProgramPipelineBindBufferRange)2109 TEST_P(ProgramPipelineTest31, ProgramPipelineBindBufferRange)
2110 {
2111     ANGLE_SKIP_TEST_IF(!IsVulkan());
2112 
2113     const GLchar *vertString = R"(#version 310 es
2114 in vec4 position;
2115 layout(std140, binding = 0) uniform ubo1 {
2116     vec4 color;
2117 };
2118 layout(location=0) out vec4 vsColor;
2119 void main()
2120 {
2121     vsColor = color;
2122     gl_Position = position;
2123 })";
2124 
2125     const GLchar *fragString = R"(#version 310 es
2126 precision mediump float;
2127 layout(std140, binding = 1) uniform globals {
2128     vec4 fsColor;
2129 };
2130 layout(std140, binding = 2) uniform params {
2131     vec4 foo;
2132 };
2133 layout(std140, binding = 3) uniform layer {
2134     vec4 bar;
2135 };
2136 layout(location=0) highp in vec4 vsColor;
2137 layout(location=0) out vec4 diffuse;
2138 void main()
2139 {
2140     diffuse = vsColor + fsColor;
2141 })";
2142 
2143     // Create the pipeline
2144     GLProgramPipeline programPipeline;
2145     glBindProgramPipeline(programPipeline);
2146 
2147     // Create the vertex shader
2148     GLShader vertShader(GL_VERTEX_SHADER);
2149     glShaderSource(vertShader, 1, &vertString, nullptr);
2150     glCompileShader(vertShader);
2151     mVertProg = glCreateProgram();
2152     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, 1);
2153     glAttachShader(mVertProg, vertShader);
2154     glLinkProgram(mVertProg);
2155     glUseProgramStages(programPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
2156     EXPECT_GL_NO_ERROR();
2157 
2158     // Create the fragment shader
2159     GLShader fragShader(GL_FRAGMENT_SHADER);
2160     glShaderSource(fragShader, 1, &fragString, nullptr);
2161     glCompileShader(fragShader);
2162     mFragProg = glCreateProgram();
2163     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, 1);
2164     glAttachShader(mFragProg, fragShader);
2165     glLinkProgram(mFragProg);
2166     glUseProgramStages(programPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
2167     EXPECT_GL_NO_ERROR();
2168 
2169     // Set up a uniform buffer with room for five offsets, four active at a time
2170     GLBuffer ubo;
2171     glBindBuffer(GL_UNIFORM_BUFFER, ubo);
2172     glBufferData(GL_UNIFORM_BUFFER, 2048, 0, GL_DYNAMIC_DRAW);
2173     uint8_t *mappedBuffer =
2174         static_cast<uint8_t *>(glMapBufferRange(GL_UNIFORM_BUFFER, 0, 2048, GL_MAP_WRITE_BIT));
2175     ASSERT_NE(nullptr, mappedBuffer);
2176 
2177     // Only set up three of the five offsets. The other two must be present, but unused.
2178     GLColor32F *binding0 = reinterpret_cast<GLColor32F *>(mappedBuffer);
2179     GLColor32F *binding1 = reinterpret_cast<GLColor32F *>(mappedBuffer + 256);
2180     GLColor32F *binding4 = reinterpret_cast<GLColor32F *>(mappedBuffer + 1024);
2181     *binding0            = kFloatRed;
2182     *binding1            = kFloatGreen;
2183     *binding4            = kFloatBlue;
2184     glUnmapBuffer(GL_UNIFORM_BUFFER);
2185 
2186     // Start with binding0=red and binding1=green
2187     glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, 0, 256);
2188     glBindBufferRange(GL_UNIFORM_BUFFER, 1, ubo, 256, 512);
2189     glBindBufferRange(GL_UNIFORM_BUFFER, 2, ubo, 512, 768);
2190     glBindBufferRange(GL_UNIFORM_BUFFER, 3, ubo, 768, 1024);
2191     EXPECT_GL_NO_ERROR();
2192 
2193     // Set up data for draw
2194     std::array<Vector3, 6> verts = GetQuadVertices();
2195     GLBuffer vbo;
2196     glBindBuffer(GL_ARRAY_BUFFER, vbo);
2197     glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
2198     GLint posLoc = glGetAttribLocation(mVertProg, "position");
2199     glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
2200     glEnableVertexAttribArray(posLoc);
2201     EXPECT_GL_NO_ERROR();
2202 
2203     // Perform the first draw
2204     glDrawArrays(GL_TRIANGLES, 0, 6);
2205 
2206     // At this point we have red+green=yellow, but read-back changes dirty bits and breaks the test
2207     // EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
2208     EXPECT_GL_NO_ERROR();
2209 
2210     // This is the key here - call glBindBufferRange between glDraw* calls, changing binding0=blue
2211     glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, 1024, 1280);
2212     EXPECT_GL_NO_ERROR();
2213 
2214     // The next draw would crash in handleDirtyGraphicsUniformBuffers without the accompanying fix
2215     glDrawArrays(GL_TRIANGLES, 0, 6);
2216 
2217     // We should now have green+blue=cyan
2218     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
2219     EXPECT_GL_NO_ERROR();
2220 }
2221 
2222 class ProgramPipelineTest32 : public ProgramPipelineTest
2223 {
2224   protected:
testTearDown()2225     void testTearDown() override
2226     {
2227         glDeleteProgram(mVertProg);
2228         glDeleteProgram(mFragProg);
2229         glDeleteProgramPipelines(1, &mPipeline);
2230     }
2231 
2232     void bindProgramPipeline(const GLchar *vertString,
2233                              const GLchar *fragString,
2234                              const GLchar *geomString);
2235     void drawQuadWithPPO(const std::string &positionAttribName,
2236                          const GLfloat positionAttribZ,
2237                          const GLfloat positionAttribXYScale);
2238 
2239     GLuint mVertProg = 0;
2240     GLuint mFragProg = 0;
2241     GLuint mGeomProg = 0;
2242     GLuint mPipeline = 0;
2243 };
2244 
bindProgramPipeline(const GLchar * vertString,const GLchar * fragString,const GLchar * geomString)2245 void ProgramPipelineTest32::bindProgramPipeline(const GLchar *vertString,
2246                                                 const GLchar *fragString,
2247                                                 const GLchar *geomString)
2248 {
2249     mVertProg = createShaderProgram(GL_VERTEX_SHADER, vertString);
2250     ASSERT_NE(mVertProg, 0u);
2251     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, fragString);
2252     ASSERT_NE(mFragProg, 0u);
2253     mGeomProg = createShaderProgram(GL_GEOMETRY_SHADER, geomString);
2254     ASSERT_NE(mGeomProg, 0u);
2255 
2256     // Generate a program pipeline and attach the programs to their respective stages
2257     glGenProgramPipelines(1, &mPipeline);
2258     EXPECT_GL_NO_ERROR();
2259     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
2260     EXPECT_GL_NO_ERROR();
2261     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
2262     EXPECT_GL_NO_ERROR();
2263     glUseProgramStages(mPipeline, GL_GEOMETRY_SHADER_BIT, mGeomProg);
2264     EXPECT_GL_NO_ERROR();
2265     glBindProgramPipeline(mPipeline);
2266     EXPECT_GL_NO_ERROR();
2267 }
2268 
2269 // Verify that we can have the max amount of uniforms with a geometry shader as part of a program
2270 // pipeline.
TEST_P(ProgramPipelineTest32,MaxGeometryImageUniforms)2271 TEST_P(ProgramPipelineTest32, MaxGeometryImageUniforms)
2272 {
2273     ANGLE_SKIP_TEST_IF(!IsVulkan() || !IsGLExtensionEnabled("GL_EXT_geometry_shader"));
2274 
2275     GLint maxGeometryImageUnits;
2276     glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT, &maxGeometryImageUnits);
2277 
2278     const GLchar *vertString = essl31_shaders::vs::Simple();
2279     const GLchar *fragString = R"(#version 310 es
2280 precision highp float;
2281 out vec4 my_FragColor;
2282 void main()
2283 {
2284     my_FragColor = vec4(1.0);
2285 })";
2286 
2287     std::stringstream geomStringStream;
2288 
2289     geomStringStream << R"(#version 310 es
2290 #extension GL_OES_geometry_shader : require
2291 layout (points)                   in;
2292 layout (points, max_vertices = 1) out;
2293 
2294 precision highp iimage2D;
2295 
2296 ivec4 counter = ivec4(0);
2297 )";
2298 
2299     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
2300     {
2301         geomStringStream << "layout(binding = " << index << ", r32i) uniform iimage2D img" << index
2302                          << ";" << std::endl;
2303     }
2304 
2305     geomStringStream << R"(
2306 void main()
2307 {
2308 )";
2309 
2310     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
2311     {
2312         geomStringStream << "counter += imageLoad(img" << index << ", ivec2(0, 0));" << std::endl;
2313     }
2314 
2315     geomStringStream << R"(
2316     gl_Position = vec4(float(counter.x), 0.0, 0.0, 1.0);
2317     EmitVertex();
2318 }
2319 )";
2320 
2321     bindProgramPipeline(vertString, fragString, geomStringStream.str().c_str());
2322 
2323     std::vector<GLTexture> textures(maxGeometryImageUnits);
2324     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
2325     {
2326         GLint value = index + 1;
2327 
2328         glBindTexture(GL_TEXTURE_2D, textures[index]);
2329         glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, 1, 1);
2330         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_INT, &value);
2331         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2332         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2333 
2334         glBindImageTexture(index, textures[index], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32I);
2335     }
2336 
2337     glDrawArrays(GL_POINTS, 0, 6);
2338     ASSERT_GL_NO_ERROR();
2339 }
2340 
2341 // Verify creation of seperable tessellation control shader program with transform feeback varying
TEST_P(ProgramPipelineTest32,CreateProgramWithTransformFeedbackVarying)2342 TEST_P(ProgramPipelineTest32, CreateProgramWithTransformFeedbackVarying)
2343 {
2344     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
2345 
2346     const char *kVS =
2347         "#version 320 es\n"
2348         "\n"
2349         "#extension GL_EXT_shader_io_blocks : require\n"
2350         "\n"
2351         "precision highp float;\n"
2352 
2353         "out BLOCK_INOUT { vec4 value; } user_out;\n"
2354         "\n"
2355         "void main()\n"
2356         "{\n"
2357         "    gl_Position    = vec4(1.0, 0.0, 0.0, 1.0);\n"
2358         "    user_out.value = vec4(4.0, 5.0, 6.0, 7.0);\n"
2359         "}\n";
2360 
2361     // Fragment shader body
2362     const char *kFS =
2363         "#version 320 es\n"
2364         "\n"
2365         "#extension GL_EXT_shader_io_blocks : require\n"
2366         "\n"
2367         "precision highp float;\n"
2368         "in BLOCK_INOUT { vec4 value; } user_in;\n"
2369         "\n"
2370         "void main()\n"
2371         "{\n"
2372         "}\n";
2373 
2374     // Geometry shader body
2375     const char *kGS =
2376         "#version 320 es\n"
2377         "\n"
2378         "#extension GL_EXT_geometry_shader : require\n"
2379         "\n"
2380         "layout(points)                   in;\n"
2381         "layout(points, max_vertices = 1) out;\n"
2382         "\n"
2383         "precision highp float;\n"
2384         "//${IN_PER_VERTEX_DECL_ARRAY}\n"
2385         "//${OUT_PER_VERTEX_DECL}\n"
2386         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
2387         "out BLOCK_INOUT { vec4 value; } user_out;\n"
2388         "\n"
2389         "void main()\n"
2390         "{\n"
2391         "    user_out.value = vec4(1.0, 2.0, 3.0, 4.0);\n"
2392         "    gl_Position    = vec4(0.0, 0.0, 0.0, 1.0);\n"
2393         "\n"
2394         "    EmitVertex();\n"
2395         "}\n";
2396 
2397     // tessellation control shader body
2398     const char *kTCS =
2399         "#version 320 es\n"
2400         "\n"
2401         "#extension GL_EXT_tessellation_shader : require\n"
2402         "#extension GL_EXT_shader_io_blocks : require\n"
2403         "\n"
2404         "layout (vertices=4) out;\n"
2405         "\n"
2406         "precision highp float;\n"
2407         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
2408         "out BLOCK_INOUT { vec4 value; } user_out[];\n"
2409         "\n"
2410         "void main()\n"
2411         "{\n"
2412         "    gl_out   [gl_InvocationID].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
2413         "    user_out [gl_InvocationID].value       = vec4(2.0, 3.0, 4.0, 5.0);\n"
2414         "\n"
2415         "    gl_TessLevelOuter[0] = 1.0;\n"
2416         "    gl_TessLevelOuter[1] = 1.0;\n"
2417         "}\n";
2418 
2419     // Tessellation evaluation shader
2420     const char *kTES =
2421         "#version 320 es\n"
2422         "\n"
2423         "#extension GL_EXT_tessellation_shader : require\n"
2424         "#extension GL_EXT_shader_io_blocks : require\n"
2425         "\n"
2426         "layout (isolines, point_mode) in;\n"
2427         "\n"
2428         "precision highp float;\n"
2429         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
2430         "out BLOCK_INOUT { vec4 value; } user_out;\n"
2431         "\n"
2432         "void main()\n"
2433         "{\n"
2434         "    gl_Position     = gl_in[0].gl_Position;\n"
2435         "    user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n"
2436         "}\n";
2437     const GLchar *kVaryingName = "BLOCK_INOUT.value";
2438 
2439     GLuint fsProgram = createShaderProgram(GL_FRAGMENT_SHADER, kFS);
2440     ASSERT_NE(0u, fsProgram);
2441 
2442     GLuint vsProgram = createShaderProgram(GL_VERTEX_SHADER, kVS, 1, &kVaryingName);
2443     ASSERT_NE(0u, vsProgram);
2444 
2445     GLuint gsProgram = 0u;
2446     if (IsGLExtensionEnabled("GL_EXT_geometry_shader"))
2447     {
2448         gsProgram = createShaderProgram(GL_GEOMETRY_SHADER, kGS, 1, &kVaryingName);
2449         ASSERT_NE(0u, gsProgram);
2450     }
2451 
2452     GLuint tcsProgram = createShaderProgram(GL_TESS_CONTROL_SHADER, kTCS, 1, &kVaryingName);
2453     // Should fail here.
2454     ASSERT_EQ(0u, tcsProgram);
2455 
2456     // try compiling without transform feedback varying it should pass
2457     tcsProgram = createShaderProgram(GL_TESS_CONTROL_SHADER, kTCS);
2458     ASSERT_NE(0u, tcsProgram);
2459 
2460     GLuint tesProgram = createShaderProgram(GL_TESS_EVALUATION_SHADER, kTES, 1, &kVaryingName);
2461     ASSERT_NE(0u, tesProgram);
2462 
2463     glDeleteProgram(fsProgram);
2464     glDeleteProgram(vsProgram);
2465     if (gsProgram != 0u)
2466     {
2467         glDeleteProgram(gsProgram);
2468     }
2469     glDeleteProgram(tcsProgram);
2470     glDeleteProgram(tesProgram);
2471 }
2472 
2473 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest);
2474 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(ProgramPipelineTest);
2475 
2476 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest31);
2477 ANGLE_INSTANTIATE_TEST_ES31(ProgramPipelineTest31);
2478 
2479 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineXFBTest31);
2480 ANGLE_INSTANTIATE_TEST_ES31(ProgramPipelineXFBTest31);
2481 
2482 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest32);
2483 ANGLE_INSTANTIATE_TEST_ES32(ProgramPipelineTest32);
2484 
2485 }  // namespace
2486