• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
87     GLuint mFragProg;
88     GLuint mPipeline;
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     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
155     ASSERT_NE(mVertProg, 0u);
156     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
157     ASSERT_NE(mFragProg, 0u);
158 
159     if (tfVaryings.size() > 0)
160     {
161         std::vector<const char *> constCharTFVaryings;
162 
163         for (const std::string &transformFeedbackVarying : tfVaryings)
164         {
165             constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
166         }
167 
168         glTransformFeedbackVaryings(mVertProg, static_cast<GLsizei>(tfVaryings.size()),
169                                     &constCharTFVaryings[0], bufferMode);
170         glLinkProgram(mVertProg);
171     }
172     // Generate a program pipeline and attach the programs to their respective stages
173     glGenProgramPipelines(1, &mPipeline);
174     EXPECT_GL_NO_ERROR();
175     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
176     EXPECT_GL_NO_ERROR();
177     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
178     EXPECT_GL_NO_ERROR();
179     glBindProgramPipeline(mPipeline);
180     EXPECT_GL_NO_ERROR();
181 }
182 
183 // Test generate or delete program pipeline.
TEST_P(ProgramPipelineTest31,GenOrDeleteProgramPipelineTest)184 TEST_P(ProgramPipelineTest31, GenOrDeleteProgramPipelineTest)
185 {
186     ANGLE_SKIP_TEST_IF(!IsVulkan());
187 
188     GLuint pipeline;
189     glGenProgramPipelines(-1, &pipeline);
190     EXPECT_GL_ERROR(GL_INVALID_VALUE);
191     glGenProgramPipelines(0, &pipeline);
192     EXPECT_GL_NO_ERROR();
193 
194     glDeleteProgramPipelines(-1, &pipeline);
195     EXPECT_GL_ERROR(GL_INVALID_VALUE);
196     glDeleteProgramPipelines(0, &pipeline);
197     EXPECT_GL_NO_ERROR();
198 }
199 
200 // Test BindProgramPipeline.
TEST_P(ProgramPipelineTest31,BindProgramPipelineTest)201 TEST_P(ProgramPipelineTest31, BindProgramPipelineTest)
202 {
203     ANGLE_SKIP_TEST_IF(!IsVulkan());
204 
205     glBindProgramPipeline(0);
206     EXPECT_GL_NO_ERROR();
207 
208     glBindProgramPipeline(2);
209     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
210 
211     GLuint pipeline;
212     glGenProgramPipelines(1, &pipeline);
213     glBindProgramPipeline(pipeline);
214     EXPECT_GL_NO_ERROR();
215 
216     glDeleteProgramPipelines(1, &pipeline);
217     glBindProgramPipeline(pipeline);
218     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
219 }
220 
221 // Test IsProgramPipeline
TEST_P(ProgramPipelineTest31,IsProgramPipelineTest)222 TEST_P(ProgramPipelineTest31, IsProgramPipelineTest)
223 {
224     ANGLE_SKIP_TEST_IF(!IsVulkan());
225 
226     EXPECT_GL_FALSE(glIsProgramPipeline(0));
227     EXPECT_GL_NO_ERROR();
228 
229     EXPECT_GL_FALSE(glIsProgramPipeline(2));
230     EXPECT_GL_NO_ERROR();
231 
232     GLuint pipeline;
233     glGenProgramPipelines(1, &pipeline);
234     glBindProgramPipeline(pipeline);
235     EXPECT_GL_TRUE(glIsProgramPipeline(pipeline));
236     EXPECT_GL_NO_ERROR();
237 
238     glBindProgramPipeline(0);
239     glDeleteProgramPipelines(1, &pipeline);
240     EXPECT_GL_FALSE(glIsProgramPipeline(pipeline));
241     EXPECT_GL_NO_ERROR();
242 }
243 
244 // Simulates a call to glCreateShaderProgramv()
createShaderProgram(GLenum type,const GLchar * shaderString,unsigned int varyingsCount,const char * const * varyings)245 GLuint createShaderProgram(GLenum type,
246                            const GLchar *shaderString,
247                            unsigned int varyingsCount,
248                            const char *const *varyings)
249 {
250     GLShader shader(type);
251     if (!shader.get())
252     {
253         return 0;
254     }
255 
256     glShaderSource(shader, 1, &shaderString, nullptr);
257     EXPECT_GL_NO_ERROR();
258 
259     glCompileShader(shader);
260 
261     GLint compiled;
262     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
263 
264     if (!compiled)
265     {
266         GLint infoLogLength;
267         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
268         std::vector<GLchar> infoLog(infoLogLength);
269         glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog.data());
270         INFO() << "Compilation failed:\n"
271                << (infoLogLength > 0 ? infoLog.data() : "") << "\n for shader:\n"
272                << shaderString << "\n";
273         return 0;
274     }
275 
276     GLuint program = glCreateProgram();
277 
278     if (program)
279     {
280         glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
281         if (compiled)
282         {
283             glAttachShader(program, shader);
284             EXPECT_GL_NO_ERROR();
285 
286             if (varyingsCount > 0)
287             {
288                 glTransformFeedbackVaryings(program, varyingsCount, varyings, GL_SEPARATE_ATTRIBS);
289                 EXPECT_GL_NO_ERROR();
290             }
291 
292             glLinkProgram(program);
293 
294             GLint linked = 0;
295             glGetProgramiv(program, GL_LINK_STATUS, &linked);
296 
297             if (linked == 0)
298             {
299                 glDeleteProgram(program);
300                 return 0;
301             }
302             glDetachShader(program, shader);
303         }
304     }
305 
306     EXPECT_GL_NO_ERROR();
307 
308     return program;
309 }
310 
createShaderProgram(GLenum type,const GLchar * shaderString)311 GLuint createShaderProgram(GLenum type, const GLchar *shaderString)
312 {
313     return createShaderProgram(type, shaderString, 0, nullptr);
314 }
315 
drawQuadWithPPO(const std::string & positionAttribName,const GLfloat positionAttribZ,const GLfloat positionAttribXYScale)316 void ProgramPipelineTest31::drawQuadWithPPO(const std::string &positionAttribName,
317                                             const GLfloat positionAttribZ,
318                                             const GLfloat positionAttribXYScale)
319 {
320     return drawQuadPPO(mVertProg, positionAttribName, positionAttribZ, positionAttribXYScale);
321 }
322 
getAvailableProgramBinaryFormatCount() const323 GLint ProgramPipelineTest31::getAvailableProgramBinaryFormatCount() const
324 {
325     GLint formatCount = 0;
326     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
327     return formatCount;
328 }
329 
330 // Test glUseProgramStages
TEST_P(ProgramPipelineTest31,UseProgramStages)331 TEST_P(ProgramPipelineTest31, UseProgramStages)
332 {
333     ANGLE_SKIP_TEST_IF(!IsVulkan());
334 
335     // Create two separable program objects from a
336     // single source string respectively (vertSrc and fragSrc)
337     const GLchar *vertString = essl31_shaders::vs::Simple();
338     const GLchar *fragString = essl31_shaders::fs::Red();
339 
340     mVertProg = createShaderProgram(GL_VERTEX_SHADER, vertString);
341     ASSERT_NE(mVertProg, 0u);
342     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, fragString);
343     ASSERT_NE(mFragProg, 0u);
344 
345     // Generate a program pipeline and attach the programs to their respective stages
346     GLuint pipeline;
347     glGenProgramPipelines(1, &pipeline);
348     EXPECT_GL_NO_ERROR();
349     glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, mVertProg);
350     EXPECT_GL_NO_ERROR();
351     glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
352     EXPECT_GL_NO_ERROR();
353     glBindProgramPipeline(pipeline);
354     EXPECT_GL_NO_ERROR();
355 
356     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
357     ASSERT_GL_NO_ERROR();
358     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
359 }
360 
361 // Test glUseProgramStages with different programs
TEST_P(ProgramPipelineTest31,UseProgramStagesWithDifferentPrograms)362 TEST_P(ProgramPipelineTest31, UseProgramStagesWithDifferentPrograms)
363 {
364     ANGLE_SKIP_TEST_IF(!IsVulkan());
365 
366     // Create two separable program objects from a
367     // single source string respectively (vertSrc and fragSrc)
368     const GLchar *vertString  = essl31_shaders::vs::Simple();
369     const GLchar *fragString1 = R"(#version 310 es
370 precision highp float;
371 uniform float redColorIn;
372 uniform float greenColorIn;
373 out vec4 my_FragColor;
374 void main()
375 {
376     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
377 })";
378     const GLchar *fragString2 = R"(#version 310 es
379 precision highp float;
380 uniform float greenColorIn;
381 uniform float blueColorIn;
382 out vec4 my_FragColor;
383 void main()
384 {
385     my_FragColor = vec4(0.0, greenColorIn, blueColorIn, 1.0);
386 })";
387 
388     bindProgramPipeline(vertString, fragString1);
389 
390     // Set the output color to red
391     GLint location = glGetUniformLocation(mFragProg, "redColorIn");
392     glActiveShaderProgram(mPipeline, mFragProg);
393     glUniform1f(location, 1.0);
394     location = glGetUniformLocation(mFragProg, "greenColorIn");
395     glActiveShaderProgram(mPipeline, mFragProg);
396     glUniform1f(location, 0.0);
397 
398     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
399     ASSERT_GL_NO_ERROR();
400     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
401 
402     GLuint fragProg;
403     fragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString2);
404     ASSERT_NE(fragProg, 0u);
405     EXPECT_GL_NO_ERROR();
406 
407     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, fragProg);
408     EXPECT_GL_NO_ERROR();
409 
410     glClearColor(0.0, 0.0, 0.0, 0.0);
411     glClear(GL_COLOR_BUFFER_BIT);
412 
413     // Set the output color to blue
414     location = glGetUniformLocation(fragProg, "greenColorIn");
415     glActiveShaderProgram(mPipeline, fragProg);
416     glUniform1f(location, 0.0);
417     location = glGetUniformLocation(fragProg, "blueColorIn");
418     glActiveShaderProgram(mPipeline, fragProg);
419     glUniform1f(location, 1.0);
420 
421     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
422     ASSERT_GL_NO_ERROR();
423     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
424 
425     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
426     EXPECT_GL_NO_ERROR();
427 
428     glClearColor(0.0, 0.0, 0.0, 0.0);
429     glClear(GL_COLOR_BUFFER_BIT);
430 
431     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
432     ASSERT_GL_NO_ERROR();
433     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
434 
435     glDeleteProgram(mVertProg);
436     glDeleteProgram(mFragProg);
437     glDeleteProgram(fragProg);
438 }
439 
440 // Test glUseProgramStages
TEST_P(ProgramPipelineTest31,UseCreateShaderProgramv)441 TEST_P(ProgramPipelineTest31, UseCreateShaderProgramv)
442 {
443     ANGLE_SKIP_TEST_IF(!IsVulkan());
444 
445     // Create two separable program objects from a
446     // single source string respectively (vertSrc and fragSrc)
447     const GLchar *vertString = essl31_shaders::vs::Simple();
448     const GLchar *fragString = essl31_shaders::fs::Red();
449 
450     bindProgramPipeline(vertString, fragString);
451 
452     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
453     ASSERT_GL_NO_ERROR();
454     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
455 }
456 
457 // Test pipeline without vertex shader
TEST_P(ProgramPipelineTest31,PipelineWithoutVertexShader)458 TEST_P(ProgramPipelineTest31, PipelineWithoutVertexShader)
459 {
460     ANGLE_SKIP_TEST_IF(!IsVulkan());
461 
462     // Create a separable program object with a fragment shader
463     const GLchar *fragString = essl31_shaders::fs::Red();
464     mFragProg                = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
465     ASSERT_NE(mFragProg, 0u);
466 
467     // Generate a program pipeline and attach the program to it's respective stage
468     glGenProgramPipelines(1, &mPipeline);
469     EXPECT_GL_NO_ERROR();
470     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
471     EXPECT_GL_NO_ERROR();
472     glBindProgramPipeline(mPipeline);
473     EXPECT_GL_NO_ERROR();
474 
475     glDrawArrays(GL_POINTS, 0, 3);
476     ASSERT_GL_NO_ERROR();
477 }
478 
479 // Test pipeline without any shaders
TEST_P(ProgramPipelineTest31,PipelineWithoutShaders)480 TEST_P(ProgramPipelineTest31, PipelineWithoutShaders)
481 {
482     ANGLE_SKIP_TEST_IF(!IsVulkan());
483 
484     // Generate a program pipeline
485     glGenProgramPipelines(1, &mPipeline);
486     EXPECT_GL_NO_ERROR();
487 
488     glBindProgramPipeline(mPipeline);
489     EXPECT_GL_NO_ERROR();
490 
491     glDrawArrays(GL_POINTS, 0, 3);
492     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
493 
494     // Ensure validation fails
495     GLint value;
496     glValidateProgramPipeline(mPipeline);
497     glGetProgramPipelineiv(mPipeline, GL_VALIDATE_STATUS, &value);
498     EXPECT_FALSE(value);
499 }
500 
501 // Test glUniform
TEST_P(ProgramPipelineTest31,FragmentStageUniformTest)502 TEST_P(ProgramPipelineTest31, FragmentStageUniformTest)
503 {
504     ANGLE_SKIP_TEST_IF(!IsVulkan());
505 
506     // Create two separable program objects from a
507     // single source string respectively (vertSrc and fragSrc)
508     const GLchar *vertString = essl31_shaders::vs::Simple();
509     const GLchar *fragString = R"(#version 310 es
510 precision highp float;
511 uniform float redColorIn;
512 uniform float greenColorIn;
513 out vec4 my_FragColor;
514 void main()
515 {
516     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
517 })";
518 
519     bindProgramPipeline(vertString, fragString);
520 
521     // Set the output color to yellow
522     GLint location = glGetUniformLocation(mFragProg, "redColorIn");
523     glActiveShaderProgram(mPipeline, mFragProg);
524     glUniform1f(location, 1.0);
525     location = glGetUniformLocation(mFragProg, "greenColorIn");
526     glActiveShaderProgram(mPipeline, mFragProg);
527     glUniform1f(location, 1.0);
528 
529     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
530     ASSERT_GL_NO_ERROR();
531     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
532 
533     glClearColor(0.0, 0.0, 0.0, 0.0);
534     glClear(GL_COLOR_BUFFER_BIT);
535 
536     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
537     ASSERT_GL_NO_ERROR();
538     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
539 
540     glClearColor(0.0, 0.0, 0.0, 0.0);
541     glClear(GL_COLOR_BUFFER_BIT);
542 
543     // Set the output color to red
544     location = glGetUniformLocation(mFragProg, "redColorIn");
545     glActiveShaderProgram(mPipeline, mFragProg);
546     glUniform1f(location, 1.0);
547     location = glGetUniformLocation(mFragProg, "greenColorIn");
548     glActiveShaderProgram(mPipeline, mFragProg);
549     glUniform1f(location, 0.0);
550 
551     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
552     ASSERT_GL_NO_ERROR();
553     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
554 
555     glDeleteProgram(mVertProg);
556     glDeleteProgram(mFragProg);
557 }
558 
559 // Test glUniformBlockBinding and then glBufferData
TEST_P(ProgramPipelineTest31,FragmentStageUniformBlockBufferDataTest)560 TEST_P(ProgramPipelineTest31, FragmentStageUniformBlockBufferDataTest)
561 {
562     ANGLE_SKIP_TEST_IF(!IsVulkan());
563 
564     // Create two separable program objects from a
565     // single source string respectively (vertSrc and fragSrc)
566     const GLchar *vertString = essl31_shaders::vs::Simple();
567     const GLchar *fragString = R"(#version 310 es
568 precision highp float;
569 layout (std140) uniform color_ubo
570 {
571     float redColorIn;
572     float greenColorIn;
573 };
574 
575 out vec4 my_FragColor;
576 void main()
577 {
578     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
579 })";
580 
581     bindProgramPipeline(vertString, fragString);
582 
583     // Set the output color to yellow
584     glActiveShaderProgram(mPipeline, mFragProg);
585     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
586     GLBuffer uboBuf;
587     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf);
588     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
589     glUniformBlockBinding(mFragProg, uboIndex, 0);
590     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
591     ASSERT_GL_NO_ERROR();
592     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
593 
594     // Clear and test again
595     glClearColor(0.0, 0.0, 0.0, 0.0);
596     glClear(GL_COLOR_BUFFER_BIT);
597     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
598     // Set the output color to red
599     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
600     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf);
601     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
602     ASSERT_GL_NO_ERROR();
603     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
604 
605     glDeleteProgram(mVertProg);
606     glDeleteProgram(mFragProg);
607 }
608 
609 // Test glUniformBlockBinding and followed by glBindBufferRange
TEST_P(ProgramPipelineTest31,FragmentStageUniformBlockBindBufferRangeTest)610 TEST_P(ProgramPipelineTest31, FragmentStageUniformBlockBindBufferRangeTest)
611 {
612     ANGLE_SKIP_TEST_IF(!IsVulkan());
613 
614     // Create two separable program objects from a
615     // single source string respectively (vertSrc and fragSrc)
616     const GLchar *vertString = essl31_shaders::vs::Simple();
617     const GLchar *fragString = R"(#version 310 es
618 precision highp float;
619 layout (std140) uniform color_ubo
620 {
621     float redColorIn;
622     float greenColorIn;
623 };
624 
625 out vec4 my_FragColor;
626 void main()
627 {
628     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
629 })";
630 
631     // Setup two uniform buffers, one with red and one with green
632     GLBuffer uboBufRed;
633     glBindBuffer(GL_UNIFORM_BUFFER, uboBufRed);
634     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
635     GLBuffer uboBufGreen;
636     glBindBuffer(GL_UNIFORM_BUFFER, uboBufGreen);
637     glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
638 
639     // Setup pipeline program using red uniform buffer
640     bindProgramPipeline(vertString, fragString);
641     glActiveShaderProgram(mPipeline, mFragProg);
642     GLint uboIndex = glGetUniformBlockIndex(mFragProg, "color_ubo");
643     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufRed);
644     glUniformBlockBinding(mFragProg, uboIndex, 0);
645     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
646     ASSERT_GL_NO_ERROR();
647     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
648 
649     // Clear and test again
650     glClearColor(0.0, 0.0, 0.0, 0.0);
651     glClear(GL_COLOR_BUFFER_BIT);
652     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
653     // bind to green uniform buffer
654     glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBufGreen);
655     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
656     ASSERT_GL_NO_ERROR();
657     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
658 
659     glDeleteProgram(mVertProg);
660     glDeleteProgram(mFragProg);
661 }
662 
663 // Test varyings
TEST_P(ProgramPipelineTest31,ProgramPipelineVaryings)664 TEST_P(ProgramPipelineTest31, ProgramPipelineVaryings)
665 {
666     ANGLE_SKIP_TEST_IF(!IsVulkan());
667 
668     // Create two separable program objects from a
669     // single source string respectively (vertSrc and fragSrc)
670     const GLchar *vertString = essl31_shaders::vs::Passthrough();
671     const GLchar *fragString = R"(#version 310 es
672 precision highp float;
673 in vec4 v_position;
674 out vec4 my_FragColor;
675 void main()
676 {
677     my_FragColor = round(v_position);
678 })";
679 
680     bindProgramPipeline(vertString, fragString);
681 
682     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
683     ASSERT_GL_NO_ERROR();
684 
685     int w = getWindowWidth() - 2;
686     int h = getWindowHeight() - 2;
687 
688     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
689     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::red);
690     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::green);
691     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
692 }
693 
694 // Creates a program pipeline with a 2D texture and renders with it.
TEST_P(ProgramPipelineTest31,DrawWith2DTexture)695 TEST_P(ProgramPipelineTest31, DrawWith2DTexture)
696 {
697     ANGLE_SKIP_TEST_IF(!IsVulkan());
698 
699     const GLchar *vertString = R"(#version 310 es
700 precision highp float;
701 in vec4 a_position;
702 out vec2 texCoord;
703 void main()
704 {
705     gl_Position = a_position;
706     texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
707 })";
708 
709     const GLchar *fragString = R"(#version 310 es
710 precision highp float;
711 in vec2 texCoord;
712 uniform sampler2D tex;
713 out vec4 my_FragColor;
714 void main()
715 {
716     my_FragColor = texture(tex, texCoord);
717 })";
718 
719     std::array<GLColor, 4> colors = {
720         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
721 
722     GLTexture tex;
723     glBindTexture(GL_TEXTURE_2D, tex);
724     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
725     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
726     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
727 
728     bindProgramPipeline(vertString, fragString);
729 
730     drawQuadWithPPO("a_position", 0.5f, 1.0f);
731     ASSERT_GL_NO_ERROR();
732 
733     int w = getWindowWidth() - 2;
734     int h = getWindowHeight() - 2;
735 
736     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
737     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
738     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
739     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
740 }
741 
742 // Test modifying a shader after it has been detached from a pipeline
TEST_P(ProgramPipelineTest31,DetachAndModifyShader)743 TEST_P(ProgramPipelineTest31, DetachAndModifyShader)
744 {
745     ANGLE_SKIP_TEST_IF(!IsVulkan());
746 
747     const GLchar *vertString = essl31_shaders::vs::Simple();
748     const GLchar *fragString = essl31_shaders::fs::Green();
749 
750     GLShader vertShader(GL_VERTEX_SHADER);
751     GLShader fragShader(GL_FRAGMENT_SHADER);
752     mVertProg = glCreateProgram();
753     mFragProg = glCreateProgram();
754 
755     // Compile and link a separable vertex shader
756     glShaderSource(vertShader, 1, &vertString, nullptr);
757     glCompileShader(vertShader);
758     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
759     glAttachShader(mVertProg, vertShader);
760     glLinkProgram(mVertProg);
761     EXPECT_GL_NO_ERROR();
762 
763     // Compile and link a separable fragment shader
764     glShaderSource(fragShader, 1, &fragString, nullptr);
765     glCompileShader(fragShader);
766     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
767     glAttachShader(mFragProg, fragShader);
768     glLinkProgram(mFragProg);
769     EXPECT_GL_NO_ERROR();
770 
771     // Generate a program pipeline and attach the programs
772     glGenProgramPipelines(1, &mPipeline);
773     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
774     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
775     glBindProgramPipeline(mPipeline);
776     EXPECT_GL_NO_ERROR();
777 
778     // Draw once to ensure this worked fine
779     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
780     ASSERT_GL_NO_ERROR();
781     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
782 
783     // Detach the fragment shader and modify it such that it no longer fits with this pipeline
784     glDetachShader(mFragProg, fragShader);
785 
786     // Add an input to the fragment shader, which will make it incompatible
787     const GLchar *fragString2 = R"(#version 310 es
788 precision highp float;
789 in vec4 color;
790 out vec4 my_FragColor;
791 void main()
792 {
793     my_FragColor = color;
794 })";
795     glShaderSource(fragShader, 1, &fragString2, nullptr);
796     glCompileShader(fragShader);
797 
798     // Link and draw with the program again, which should be fine since the shader was detached
799     glLinkProgram(mFragProg);
800 
801     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
802     ASSERT_GL_NO_ERROR();
803 }
804 
805 // Test binding two programs that use a texture as different types
TEST_P(ProgramPipelineTest31,DifferentTextureTypes)806 TEST_P(ProgramPipelineTest31, DifferentTextureTypes)
807 {
808     // Only the Vulkan backend supports PPO
809     ANGLE_SKIP_TEST_IF(!IsVulkan());
810 
811     // Per the OpenGL ES 3.1 spec:
812     //
813     // It is not allowed to have variables of different sampler types pointing to the same texture
814     // image unit within a program object. This situation can only be detected at the next rendering
815     // command issued which triggers shader invocations, and an INVALID_OPERATION error will then
816     // be generated
817     //
818 
819     // Create a vertex shader that uses the texture as 2D
820     const GLchar *vertString = R"(#version 310 es
821 precision highp float;
822 in vec4 a_position;
823 uniform sampler2D tex2D;
824 layout(location = 0) out vec4 texColorOut;
825 layout(location = 1) out vec2 texCoordOut;
826 void main()
827 {
828     gl_Position = a_position;
829     vec2 texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
830     texColorOut = textureLod(tex2D, texCoord, 0.0);
831     texCoordOut = texCoord;
832 })";
833 
834     // Create a fragment shader that uses the texture as Cube
835     const GLchar *fragString = R"(#version 310 es
836 precision highp float;
837 layout(location = 0) in vec4 texColor;
838 layout(location = 1) in vec2 texCoord;
839 uniform samplerCube texCube;
840 out vec4 my_FragColor;
841 void main()
842 {
843     my_FragColor = texture(texCube, vec3(texCoord.x, texCoord.y, 0.0));
844 })";
845 
846     // Create and populate the 2D texture
847     std::array<GLColor, 4> colors = {
848         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
849     GLTexture tex;
850     glBindTexture(GL_TEXTURE_2D, tex);
851     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
852     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
853     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
854 
855     // Create a pipeline that uses the bad combination.  This should fail to link the pipeline.
856     bindProgramPipeline(vertString, fragString);
857     drawQuadWithPPO("a_position", 0.5f, 1.0f);
858     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
859 
860     // Update the fragment shader to correctly use 2D texture
861     const GLchar *fragString2 = R"(#version 310 es
862 precision highp float;
863 layout(location = 0) in vec4 texColor;
864 layout(location = 1) in vec2 texCoord;
865 uniform sampler2D tex2D;
866 out vec4 my_FragColor;
867 void main()
868 {
869     my_FragColor = texture(tex2D, texCoord);
870 })";
871 
872     // Bind the pipeline again, which should succeed.
873     bindProgramPipeline(vertString, fragString2);
874     drawQuadWithPPO("a_position", 0.5f, 1.0f);
875     ASSERT_GL_NO_ERROR();
876 }
877 
878 // Tests that we receive a PPO link validation error when attempting to draw with the bad PPO
TEST_P(ProgramPipelineTest31,VerifyPpoLinkErrorSignalledCorrectly)879 TEST_P(ProgramPipelineTest31, VerifyPpoLinkErrorSignalledCorrectly)
880 {
881     // Create pipeline that should fail link
882     // Bind program
883     // Draw
884     // Unbind program
885     // Draw  <<--- expect a link validation error here
886 
887     // Only the Vulkan backend supports PPOs
888     ANGLE_SKIP_TEST_IF(!IsVulkan());
889 
890     // Create two separable program objects from a
891     // single source string respectively (vertSrc and fragSrc)
892     const GLchar *vertString = essl31_shaders::vs::Simple();
893     const GLchar *fragString = essl31_shaders::fs::Red();
894     // Create a fragment shader that takes a color input
895     // This should cause the PPO link to fail, since the varyings don't match (no output from VS).
896     const GLchar *fragStringBad = R"(#version 310 es
897 precision highp float;
898 layout(location = 0) in vec4 colorIn;
899 out vec4 my_FragColor;
900 void main()
901 {
902     my_FragColor = colorIn;
903 })";
904     bindProgramPipeline(vertString, fragStringBad);
905 
906     ANGLE_GL_PROGRAM(program, vertString, fragString);
907     drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.0f, 1.0f, true);
908     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
909 
910     // Draw with the PPO, which should generate an error due to the link failure.
911     glUseProgram(0);
912     ASSERT_GL_NO_ERROR();
913     drawQuadWithPPO(essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
914     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
915 }
916 
917 // Tests creating two program pipelines with a common shader and a varying location mismatch.
TEST_P(ProgramPipelineTest31,VaryingLocationMismatch)918 TEST_P(ProgramPipelineTest31, VaryingLocationMismatch)
919 {
920     // Only the Vulkan backend supports PPOs
921     ANGLE_SKIP_TEST_IF(!IsVulkan());
922 
923     // Create a fragment shader using the varying location "5".
924     const char *kFS = R"(#version 310 es
925 precision mediump float;
926 layout(location = 5) in vec4 color;
927 out vec4 colorOut;
928 void main()
929 {
930     colorOut = color;
931 })";
932 
933     // Create a pipeline with a vertex shader using varying location "5". Should succeed.
934     const char *kVSGood = R"(#version 310 es
935 precision mediump float;
936 layout(location = 5) out vec4 color;
937 in vec4 position;
938 uniform float uniOne;
939 void main()
940 {
941     gl_Position = position;
942     color = vec4(0, uniOne, 0, 1);
943 })";
944 
945     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &kVSGood);
946     ASSERT_NE(mVertProg, 0u);
947     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &kFS);
948     ASSERT_NE(mFragProg, 0u);
949 
950     // Generate a program pipeline and attach the programs to their respective stages
951     glGenProgramPipelines(1, &mPipeline);
952     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
953     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
954     glBindProgramPipeline(mPipeline);
955     ASSERT_GL_NO_ERROR();
956 
957     GLint location = glGetUniformLocation(mVertProg, "uniOne");
958     ASSERT_NE(-1, location);
959     glActiveShaderProgram(mPipeline, mVertProg);
960     glUniform1f(location, 1.0);
961     ASSERT_GL_NO_ERROR();
962 
963     drawQuadWithPPO("position", 0.5f, 1.0f);
964     ASSERT_GL_NO_ERROR();
965 
966     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
967 
968     // Create a pipeline with a vertex shader using varying location "3". Should fail.
969     const char *kVSBad = R"(#version 310 es
970 precision mediump float;
971 layout(location = 3) out vec4 color;
972 in vec4 position;
973 uniform float uniOne;
974 void main()
975 {
976     gl_Position = position;
977     color = vec4(0, uniOne, 0, 1);
978 })";
979 
980     glDeleteProgram(mVertProg);
981     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &kVSBad);
982     ASSERT_NE(mVertProg, 0u);
983 
984     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
985     ASSERT_GL_NO_ERROR();
986 
987     drawQuadWithPPO("position", 0.5f, 1.0f);
988     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
989 }
990 
991 // Test that uniform updates are propagated with minimal state changes.
TEST_P(ProgramPipelineTest31,UniformUpdate)992 TEST_P(ProgramPipelineTest31, UniformUpdate)
993 {
994     ANGLE_SKIP_TEST_IF(!IsVulkan());
995 
996     // Create two separable program objects from a
997     // single source string respectively (vertSrc and fragSrc)
998     const GLchar *vertString = essl31_shaders::vs::Simple();
999     const GLchar *fragString = R"(#version 310 es
1000 precision highp float;
1001 uniform float redColorIn;
1002 uniform float greenColorIn;
1003 out vec4 my_FragColor;
1004 void main()
1005 {
1006     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
1007 })";
1008 
1009     bindProgramPipeline(vertString, fragString);
1010 
1011     GLint redLoc = glGetUniformLocation(mFragProg, "redColorIn");
1012     ASSERT_NE(-1, redLoc);
1013     GLint greenLoc = glGetUniformLocation(mFragProg, "greenColorIn");
1014     ASSERT_NE(-1, greenLoc);
1015 
1016     glActiveShaderProgram(mPipeline, mFragProg);
1017 
1018     std::array<Vector3, 6> verts = GetQuadVertices();
1019 
1020     GLBuffer vbo;
1021     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1022     glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
1023 
1024     GLint posLoc = glGetAttribLocation(mVertProg, essl31_shaders::PositionAttrib());
1025     glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1026     glEnableVertexAttribArray(posLoc);
1027 
1028     glClearColor(0.0, 0.0, 0.0, 0.0);
1029     glClear(GL_COLOR_BUFFER_BIT);
1030 
1031     // Set the output color to red, draw to left half of window.
1032     glUniform1f(redLoc, 1.0);
1033     glUniform1f(greenLoc, 0.0);
1034     glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
1035     glDrawArrays(GL_TRIANGLES, 0, 6);
1036     ASSERT_GL_NO_ERROR();
1037 
1038     // Set the output color to green, draw to right half of window.
1039     glUniform1f(redLoc, 0.0);
1040     glUniform1f(greenLoc, 1.0);
1041 
1042     glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight());
1043     glDrawArrays(GL_TRIANGLES, 0, 6);
1044     ASSERT_GL_NO_ERROR();
1045 
1046     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1047     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 + 1, 0, GLColor::green);
1048 }
1049 
1050 // Test that uniform updates propagate to two pipelines.
TEST_P(ProgramPipelineTest31,UniformUpdateTwoPipelines)1051 TEST_P(ProgramPipelineTest31, UniformUpdateTwoPipelines)
1052 {
1053     ANGLE_SKIP_TEST_IF(!IsVulkan());
1054 
1055     // Create two separable program objects from a
1056     // single source string respectively (vertSrc and fragSrc)
1057     const GLchar *vertString = essl31_shaders::vs::Simple();
1058     const GLchar *fragString = R"(#version 310 es
1059 precision highp float;
1060 uniform float redColorIn;
1061 uniform float greenColorIn;
1062 out vec4 my_FragColor;
1063 void main()
1064 {
1065     my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
1066 })";
1067 
1068     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
1069     ASSERT_NE(mVertProg, 0u);
1070     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
1071     ASSERT_NE(mFragProg, 0u);
1072 
1073     GLint redLoc = glGetUniformLocation(mFragProg, "redColorIn");
1074     ASSERT_NE(-1, redLoc);
1075     GLint greenLoc = glGetUniformLocation(mFragProg, "greenColorIn");
1076     ASSERT_NE(-1, greenLoc);
1077 
1078     GLProgramPipeline ppo1;
1079     glUseProgramStages(ppo1, GL_VERTEX_SHADER_BIT, mVertProg);
1080     glUseProgramStages(ppo1, GL_FRAGMENT_SHADER_BIT, mFragProg);
1081     glBindProgramPipeline(ppo1);
1082     glActiveShaderProgram(ppo1, mFragProg);
1083     ASSERT_GL_NO_ERROR();
1084 
1085     GLProgramPipeline ppo2;
1086     glUseProgramStages(ppo2, GL_VERTEX_SHADER_BIT, mVertProg);
1087     glUseProgramStages(ppo2, GL_FRAGMENT_SHADER_BIT, mFragProg);
1088     glBindProgramPipeline(ppo2);
1089     glActiveShaderProgram(ppo2, mFragProg);
1090     ASSERT_GL_NO_ERROR();
1091 
1092     std::array<Vector3, 6> verts = GetQuadVertices();
1093 
1094     GLBuffer vbo;
1095     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1096     glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
1097 
1098     GLint posLoc = glGetAttribLocation(mVertProg, essl31_shaders::PositionAttrib());
1099     glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1100     glEnableVertexAttribArray(posLoc);
1101 
1102     glClearColor(0.0, 0.0, 0.0, 0.0);
1103     glClear(GL_COLOR_BUFFER_BIT);
1104 
1105     const GLsizei w = getWindowWidth() / 2;
1106     const GLsizei h = getWindowHeight() / 2;
1107 
1108     // Set the output color to red, draw to UL quad of window with first PPO.
1109     glUniform1f(redLoc, 1.0);
1110     glUniform1f(greenLoc, 0.0);
1111     glBindProgramPipeline(ppo1);
1112     glViewport(0, 0, w, h);
1113     glDrawArrays(GL_TRIANGLES, 0, 6);
1114     ASSERT_GL_NO_ERROR();
1115 
1116     // Draw red to UR half of window with second PPO.
1117     glBindProgramPipeline(ppo2);
1118     glViewport(w, 0, w, h);
1119     glDrawArrays(GL_TRIANGLES, 0, 6);
1120     ASSERT_GL_NO_ERROR();
1121 
1122     // Draw green to LL corner of window with first PPO.
1123     glUniform1f(redLoc, 0.0);
1124     glUniform1f(greenLoc, 1.0);
1125     glBindProgramPipeline(ppo1);
1126     glViewport(0, h, w, h);
1127     glDrawArrays(GL_TRIANGLES, 0, 6);
1128     ASSERT_GL_NO_ERROR();
1129 
1130     // Draw green to LR half of window with second PPO.
1131     glBindProgramPipeline(ppo2);
1132     glViewport(w, h, w, h);
1133     glDrawArrays(GL_TRIANGLES, 0, 6);
1134     ASSERT_GL_NO_ERROR();
1135 
1136     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1137     EXPECT_PIXEL_COLOR_EQ(w + 1, 0, GLColor::red);
1138     EXPECT_PIXEL_COLOR_EQ(0, h + 1, GLColor::green);
1139     EXPECT_PIXEL_COLOR_EQ(w + 1, h + 1, GLColor::green);
1140 }
1141 
1142 // Tests that setting sampler bindings on a program before the pipeline works as expected.
TEST_P(ProgramPipelineTest31,BindSamplerBeforeCreatingPipeline)1143 TEST_P(ProgramPipelineTest31, BindSamplerBeforeCreatingPipeline)
1144 {
1145     ANGLE_SKIP_TEST_IF(!IsVulkan());
1146 
1147     // Create two textures - red and green.
1148     GLTexture redTex;
1149     glBindTexture(GL_TEXTURE_2D, redTex);
1150     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
1151     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1152     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1153 
1154     GLTexture greenTex;
1155     glBindTexture(GL_TEXTURE_2D, greenTex);
1156     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1157     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1158     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1159 
1160     // Bind red to texture unit 0 and green to unit 1.
1161     glActiveTexture(GL_TEXTURE0);
1162     glBindTexture(GL_TEXTURE_2D, redTex);
1163 
1164     glActiveTexture(GL_TEXTURE1);
1165     glBindTexture(GL_TEXTURE_2D, greenTex);
1166 
1167     // Create the separable programs.
1168     const char *vsSource = essl1_shaders::vs::Texture2D();
1169     mVertProg            = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vsSource);
1170     ASSERT_NE(0u, mVertProg);
1171 
1172     const char *fsSource = essl1_shaders::fs::Texture2D();
1173     mFragProg            = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fsSource);
1174     ASSERT_NE(0u, mFragProg);
1175 
1176     // Set the program to sample from the green texture.
1177     GLint texLoc = glGetUniformLocation(mFragProg, essl1_shaders::Texture2DUniform());
1178     ASSERT_NE(-1, texLoc);
1179 
1180     glUseProgram(mFragProg);
1181     glUniform1i(texLoc, 1);
1182 
1183     ASSERT_GL_NO_ERROR();
1184 
1185     // Create and draw with the pipeline.
1186     GLProgramPipeline ppo;
1187     glUseProgramStages(ppo, GL_VERTEX_SHADER_BIT, mVertProg);
1188     glUseProgramStages(ppo, GL_FRAGMENT_SHADER_BIT, mFragProg);
1189     glBindProgramPipeline(ppo);
1190 
1191     ASSERT_GL_NO_ERROR();
1192 
1193     drawQuadWithPPO(essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
1194     ASSERT_GL_NO_ERROR();
1195 
1196     // We should have sampled from the second texture bound to unit 1.
1197     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1198 }
1199 
1200 // Test that a shader IO block varying with separable program links
1201 // successfully.
TEST_P(ProgramPipelineTest31,VaryingIOBlockSeparableProgram)1202 TEST_P(ProgramPipelineTest31, VaryingIOBlockSeparableProgram)
1203 {
1204     // Only the Vulkan backend supports PPOs
1205     ANGLE_SKIP_TEST_IF(!IsVulkan());
1206     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
1207 
1208     constexpr char kVS[] =
1209         R"(#version 310 es
1210         #extension GL_EXT_shader_io_blocks : require
1211 
1212         precision highp float;
1213         in vec4 inputAttribute;
1214         out Block_inout { vec4 value; } user_out;
1215 
1216         void main()
1217         {
1218             gl_Position    = inputAttribute;
1219             user_out.value = vec4(4.0, 5.0, 6.0, 7.0);
1220         })";
1221 
1222     constexpr char kFS[] =
1223         R"(#version 310 es
1224         #extension GL_EXT_shader_io_blocks : require
1225 
1226         precision highp float;
1227         layout(location = 0) out mediump vec4 color;
1228         in Block_inout { vec4 value; } user_in;
1229 
1230         void main()
1231         {
1232             color = vec4(1, 0, 0, 1);
1233         })";
1234 
1235     bindProgramPipeline(kVS, kFS);
1236     drawQuadWithPPO("inputAttribute", 0.5f, 1.0f);
1237     ASSERT_GL_NO_ERROR();
1238     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1239 }
1240 
1241 // Test that a shader IO block varying with separable program links
1242 // successfully.
TEST_P(ProgramPipelineXFBTest31,VaryingIOBlockSeparableProgramWithXFB)1243 TEST_P(ProgramPipelineXFBTest31, VaryingIOBlockSeparableProgramWithXFB)
1244 {
1245     // Only the Vulkan backend supports PPOs
1246     ANGLE_SKIP_TEST_IF(!IsVulkan());
1247     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
1248     // http://anglebug.com/5486
1249     ANGLE_SKIP_TEST_IF(IsVulkan());
1250 
1251     constexpr char kVS[] =
1252         R"(#version 310 es
1253         #extension GL_EXT_shader_io_blocks : require
1254 
1255         precision highp float;
1256         in vec4 inputAttribute;
1257         out Block_inout { vec4 value; } user_out;
1258 
1259         void main()
1260         {
1261             gl_Position    = inputAttribute;
1262             user_out.value = vec4(4.0, 5.0, 6.0, 7.0);
1263         })";
1264 
1265     constexpr char kFS[] =
1266         R"(#version 310 es
1267         #extension GL_EXT_shader_io_blocks : require
1268 
1269         precision highp float;
1270         layout(location = 0) out mediump vec4 color;
1271         in Block_inout { vec4 value; } user_in;
1272 
1273         void main()
1274         {
1275             color = vec4(1, 0, 0, 1);
1276         })";
1277     std::vector<std::string> tfVaryings;
1278     tfVaryings.push_back("Block_inout.value");
1279     bindProgramPipelineWithXFBVaryings(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
1280     glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
1281 
1282     glBeginTransformFeedback(GL_TRIANGLES);
1283     drawQuadWithPPO("inputAttribute", 0.5f, 1.0f);
1284     glEndTransformFeedback();
1285 
1286     ASSERT_GL_NO_ERROR();
1287     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1288 
1289     void *mappedBuffer =
1290         glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 4, GL_MAP_READ_BIT);
1291     ASSERT_NE(nullptr, mappedBuffer);
1292 
1293     float *mappedFloats = static_cast<float *>(mappedBuffer);
1294     for (unsigned int cnt = 0; cnt < 4; ++cnt)
1295     {
1296         EXPECT_EQ(4 + cnt, mappedFloats[cnt]);
1297     }
1298     glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1299 
1300     EXPECT_GL_NO_ERROR();
1301 }
1302 
1303 // Test modifying a shader and re-linking it updates the PPO too
TEST_P(ProgramPipelineTest31,ModifyAndRelinkShader)1304 TEST_P(ProgramPipelineTest31, ModifyAndRelinkShader)
1305 {
1306     ANGLE_SKIP_TEST_IF(!IsVulkan());
1307 
1308     const GLchar *vertString      = essl31_shaders::vs::Simple();
1309     const GLchar *fragStringGreen = essl31_shaders::fs::Green();
1310     const GLchar *fragStringRed   = essl31_shaders::fs::Red();
1311 
1312     GLShader vertShader(GL_VERTEX_SHADER);
1313     GLShader fragShader(GL_FRAGMENT_SHADER);
1314     mVertProg = glCreateProgram();
1315     mFragProg = glCreateProgram();
1316 
1317     // Compile and link a separable vertex shader
1318     glShaderSource(vertShader, 1, &vertString, nullptr);
1319     glCompileShader(vertShader);
1320     glProgramParameteri(mVertProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1321     glAttachShader(mVertProg, vertShader);
1322     glLinkProgram(mVertProg);
1323     EXPECT_GL_NO_ERROR();
1324 
1325     // Compile and link a separable fragment shader
1326     glShaderSource(fragShader, 1, &fragStringGreen, nullptr);
1327     glCompileShader(fragShader);
1328     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1329     glAttachShader(mFragProg, fragShader);
1330     glLinkProgram(mFragProg);
1331     EXPECT_GL_NO_ERROR();
1332 
1333     // Generate a program pipeline and attach the programs
1334     glGenProgramPipelines(1, &mPipeline);
1335     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1336     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1337     glBindProgramPipeline(mPipeline);
1338     EXPECT_GL_NO_ERROR();
1339 
1340     // Draw once to ensure this worked fine
1341     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1342     ASSERT_GL_NO_ERROR();
1343     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1344 
1345     // Detach the fragment shader and modify it such that it no longer fits with this pipeline
1346     glDetachShader(mFragProg, fragShader);
1347 
1348     // Modify the FS and re-link it
1349     glShaderSource(fragShader, 1, &fragStringRed, nullptr);
1350     glCompileShader(fragShader);
1351     glProgramParameteri(mFragProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
1352     glAttachShader(mFragProg, fragShader);
1353     glLinkProgram(mFragProg);
1354     EXPECT_GL_NO_ERROR();
1355 
1356     // Draw with the PPO again and verify it's now red
1357     drawQuadWithPPO(essl31_shaders::PositionAttrib(), 0.5f, 1.0f);
1358     ASSERT_GL_NO_ERROR();
1359     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1360 }
1361 
1362 // Test that a PPO can be used when the attached shader programs are created with glProgramBinary().
1363 // This validates the necessary programs' information is serialized/deserialized so they can be
1364 // linked by the PPO during glDrawArrays.
TEST_P(ProgramPipelineTest31,ProgramBinary)1365 TEST_P(ProgramPipelineTest31, ProgramBinary)
1366 {
1367     ANGLE_SKIP_TEST_IF(!IsVulkan());
1368     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1369 
1370     const GLchar *vertString = R"(#version 310 es
1371 precision highp float;
1372 in vec4 a_position;
1373 out vec2 texCoord;
1374 void main()
1375 {
1376     gl_Position = a_position;
1377     texCoord = vec2(a_position.x, a_position.y) * 0.5 + vec2(0.5);
1378 })";
1379 
1380     const GLchar *fragString = R"(#version 310 es
1381 precision highp float;
1382 in vec2 texCoord;
1383 uniform sampler2D tex;
1384 out vec4 my_FragColor;
1385 void main()
1386 {
1387     my_FragColor = texture(tex, texCoord);
1388 })";
1389 
1390     std::array<GLColor, 4> colors = {
1391         {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
1392 
1393     GLTexture tex;
1394     glBindTexture(GL_TEXTURE_2D, tex);
1395     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
1396     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1397     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1398 
1399     mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
1400     ASSERT_NE(mVertProg, 0u);
1401     mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
1402     ASSERT_NE(mFragProg, 0u);
1403 
1404     // Save the VS program binary out
1405     std::vector<uint8_t> vsBinary(0);
1406     GLint vsProgramLength = 0;
1407     GLint vsWrittenLength = 0;
1408     GLenum vsBinaryFormat = 0;
1409     glGetProgramiv(mVertProg, GL_PROGRAM_BINARY_LENGTH, &vsProgramLength);
1410     ASSERT_GL_NO_ERROR();
1411     vsBinary.resize(vsProgramLength);
1412     glGetProgramBinary(mVertProg, vsProgramLength, &vsWrittenLength, &vsBinaryFormat,
1413                        vsBinary.data());
1414     ASSERT_GL_NO_ERROR();
1415 
1416     // Save the FS program binary out
1417     std::vector<uint8_t> fsBinary(0);
1418     GLint fsProgramLength = 0;
1419     GLint fsWrittenLength = 0;
1420     GLenum fsBinaryFormat = 0;
1421     glGetProgramiv(mFragProg, GL_PROGRAM_BINARY_LENGTH, &fsProgramLength);
1422     ASSERT_GL_NO_ERROR();
1423     fsBinary.resize(fsProgramLength);
1424     glGetProgramBinary(mFragProg, fsProgramLength, &fsWrittenLength, &fsBinaryFormat,
1425                        fsBinary.data());
1426     ASSERT_GL_NO_ERROR();
1427 
1428     mVertProg = glCreateProgram();
1429     glProgramBinary(mVertProg, vsBinaryFormat, vsBinary.data(), vsWrittenLength);
1430     mFragProg = glCreateProgram();
1431     glProgramBinary(mFragProg, fsBinaryFormat, fsBinary.data(), fsWrittenLength);
1432 
1433     // Generate a program pipeline and attach the programs to their respective stages
1434     glGenProgramPipelines(1, &mPipeline);
1435     EXPECT_GL_NO_ERROR();
1436     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1437     EXPECT_GL_NO_ERROR();
1438     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1439     EXPECT_GL_NO_ERROR();
1440     glBindProgramPipeline(mPipeline);
1441     EXPECT_GL_NO_ERROR();
1442 
1443     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1444     ASSERT_GL_NO_ERROR();
1445 
1446     int w = getWindowWidth() - 2;
1447     int h = getWindowHeight() - 2;
1448 
1449     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1450     EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
1451     EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
1452     EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
1453 }
1454 
1455 // Test that updating a sampler uniform in a separable program behaves correctly with PPOs.
TEST_P(ProgramPipelineTest31,SampleTextureAThenTextureB)1456 TEST_P(ProgramPipelineTest31, SampleTextureAThenTextureB)
1457 {
1458     ANGLE_SKIP_TEST_IF(!IsVulkan());
1459 
1460     constexpr int kWidth  = 2;
1461     constexpr int kHeight = 2;
1462 
1463     const GLchar *vertString = R"(#version 310 es
1464 precision highp float;
1465 in vec2 a_position;
1466 out vec2 texCoord;
1467 void main()
1468 {
1469     gl_Position = vec4(a_position, 0, 1);
1470     texCoord = a_position * 0.5 + vec2(0.5);
1471 })";
1472 
1473     const GLchar *fragString = R"(#version 310 es
1474 precision highp float;
1475 in vec2 texCoord;
1476 uniform sampler2D tex;
1477 out vec4 my_FragColor;
1478 void main()
1479 {
1480     my_FragColor = texture(tex, texCoord);
1481 })";
1482 
1483     std::array<GLColor, kWidth *kHeight> redColor = {
1484         {GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
1485     std::array<GLColor, kWidth *kHeight> greenColor = {
1486         {GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
1487 
1488     // Create a red texture and bind to texture unit 0
1489     GLTexture redTex;
1490     glActiveTexture(GL_TEXTURE0);
1491     glBindTexture(GL_TEXTURE_2D, redTex);
1492     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1493                  redColor.data());
1494     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1495     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1496     ASSERT_GL_NO_ERROR();
1497     // Create a green texture and bind to texture unit 1
1498     GLTexture greenTex;
1499     glActiveTexture(GL_TEXTURE1);
1500     glBindTexture(GL_TEXTURE_2D, greenTex);
1501     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1502                  greenColor.data());
1503     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1504     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1505     glActiveTexture(GL_TEXTURE0);
1506     ASSERT_GL_NO_ERROR();
1507 
1508     bindProgramPipeline(vertString, fragString);
1509 
1510     GLint location1 = glGetUniformLocation(mFragProg, "tex");
1511     ASSERT_NE(location1, -1);
1512     glActiveShaderProgram(mPipeline, mFragProg);
1513     ASSERT_GL_NO_ERROR();
1514 
1515     glEnable(GL_BLEND);
1516     glBlendEquation(GL_FUNC_ADD);
1517     glBlendFunc(GL_ONE, GL_ONE);
1518 
1519     // Draw red
1520     glUniform1i(location1, 0);
1521     ASSERT_GL_NO_ERROR();
1522     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1523     ASSERT_GL_NO_ERROR();
1524 
1525     // Draw green
1526     glUniform1i(location1, 1);
1527     ASSERT_GL_NO_ERROR();
1528     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1529     ASSERT_GL_NO_ERROR();
1530 
1531     EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::yellow);
1532 }
1533 
1534 // Verify that image uniforms can be used with separable programs
TEST_P(ProgramPipelineTest31,ImageUniforms)1535 TEST_P(ProgramPipelineTest31, ImageUniforms)
1536 {
1537     ANGLE_SKIP_TEST_IF(!IsVulkan());
1538 
1539     GLint maxVertexImageUniforms;
1540     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
1541     ANGLE_SKIP_TEST_IF(maxVertexImageUniforms == 0);
1542 
1543     const GLchar *vertString = R"(#version 310 es
1544 precision highp float;
1545 precision highp image2D;
1546 layout(binding = 0, r32f) uniform image2D img;
1547 
1548 void main()
1549 {
1550     gl_Position = imageLoad(img, ivec2(0, 0));
1551 })";
1552 
1553     const GLchar *fragString = essl31_shaders::fs::Red();
1554 
1555     bindProgramPipeline(vertString, fragString);
1556 
1557     GLTexture texture;
1558     GLfloat value = 1.0;
1559 
1560     glBindTexture(GL_TEXTURE_2D, texture);
1561     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 1, 1);
1562     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED, GL_FLOAT, &value);
1563     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1564     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1565 
1566     glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1567 
1568     glDrawArrays(GL_POINTS, 0, 6);
1569     ASSERT_GL_NO_ERROR();
1570 }
1571 
1572 // Verify that image uniforms can link in separable programs
TEST_P(ProgramPipelineTest31,LinkedImageUniforms)1573 TEST_P(ProgramPipelineTest31, LinkedImageUniforms)
1574 {
1575     ANGLE_SKIP_TEST_IF(!IsVulkan());
1576 
1577     GLint maxVertexImageUniforms;
1578     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
1579     ANGLE_SKIP_TEST_IF(maxVertexImageUniforms == 0);
1580 
1581     const GLchar *vertString = R"(#version 310 es
1582 precision highp float;
1583 precision highp image2D;
1584 layout(binding = 0, r32f) uniform image2D img;
1585 
1586 void main()
1587 {
1588     vec2 position = -imageLoad(img, ivec2(0, 0)).rr;
1589     if (gl_VertexID == 1)
1590         position = vec2(3, -1);
1591     else if (gl_VertexID == 2)
1592         position = vec2(-1, 3);
1593 
1594     gl_Position = vec4(position, 0, 1);
1595 })";
1596 
1597     const GLchar *fragString = R"(#version 310 es
1598 precision highp float;
1599 precision highp image2D;
1600 layout(binding = 0, r32f) uniform image2D img;
1601 layout(location = 0) out vec4 color;
1602 
1603 void main()
1604 {
1605     color = imageLoad(img, ivec2(0, 0));
1606 })";
1607 
1608     bindProgramPipeline(vertString, fragString);
1609 
1610     GLTexture texture;
1611     GLfloat value = 1.0;
1612 
1613     glBindTexture(GL_TEXTURE_2D, texture);
1614     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 1, 1);
1615     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED, GL_FLOAT, &value);
1616     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1617     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1618 
1619     glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1620 
1621     glDrawArrays(GL_TRIANGLES, 0, 3);
1622 
1623     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1624     ASSERT_GL_NO_ERROR();
1625 }
1626 
1627 // Verify that we can have the max amount of uniform buffer objects as part of a program
1628 // pipeline.
TEST_P(ProgramPipelineTest31,MaxFragmentUniformBufferObjects)1629 TEST_P(ProgramPipelineTest31, MaxFragmentUniformBufferObjects)
1630 {
1631     ANGLE_SKIP_TEST_IF(!IsVulkan());
1632 
1633     GLint maxUniformBlocks;
1634     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &maxUniformBlocks);
1635 
1636     const GLchar *vertString = essl31_shaders::vs::Simple();
1637     std::stringstream fragStringStream;
1638     fragStringStream << R"(#version 310 es
1639 precision highp float;
1640 out vec4 my_FragColor;
1641 layout(binding = 0) uniform block {
1642     float data;
1643 } ubo[)";
1644     fragStringStream << maxUniformBlocks;
1645     fragStringStream << R"(];
1646 void main()
1647 {
1648     my_FragColor = vec4(1.0);
1649 )";
1650     for (GLint index = 0; index < maxUniformBlocks; index++)
1651     {
1652         fragStringStream << "my_FragColor.x + ubo[" << index << "].data;" << std::endl;
1653     }
1654     fragStringStream << "}" << std::endl;
1655 
1656     bindProgramPipeline(vertString, fragStringStream.str().c_str());
1657 
1658     std::vector<GLBuffer> buffers(maxUniformBlocks);
1659     for (GLint index = 0; index < maxUniformBlocks; ++index)
1660     {
1661         glBindBuffer(GL_UNIFORM_BUFFER, buffers[index]);
1662         glBufferData(GL_UNIFORM_BUFFER, sizeof(GLfloat), NULL, GL_STATIC_DRAW);
1663         glBindBufferBase(GL_UNIFORM_BUFFER, index, buffers[index]);
1664     }
1665 
1666     glDrawArrays(GL_POINTS, 0, 6);
1667     ASSERT_GL_NO_ERROR();
1668 }
1669 
1670 // Verify that we can have the max amount of shader storage buffer objects as part of a program
1671 // pipeline.
TEST_P(ProgramPipelineTest31,MaxFragmentShaderStorageBufferObjects)1672 TEST_P(ProgramPipelineTest31, MaxFragmentShaderStorageBufferObjects)
1673 {
1674     ANGLE_SKIP_TEST_IF(!IsVulkan());
1675 
1676     GLint maxShaderStorageBuffers;
1677     glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxShaderStorageBuffers);
1678     const GLchar *vertString = essl31_shaders::vs::Simple();
1679     std::stringstream fragStringStream;
1680     fragStringStream << R"(#version 310 es
1681 precision highp float;
1682 out vec4 my_FragColor;
1683 layout(binding = 0) buffer buf {
1684     float data;
1685 } ssbo[)";
1686     fragStringStream << maxShaderStorageBuffers;
1687     fragStringStream << R"(];
1688 void main()
1689 {
1690     my_FragColor = vec4(1.0);
1691 )";
1692     for (GLint index = 0; index < maxShaderStorageBuffers; index++)
1693     {
1694         fragStringStream << "my_FragColor.x + ssbo[" << index << "].data;" << std::endl;
1695     }
1696     fragStringStream << "}" << std::endl;
1697 
1698     bindProgramPipeline(vertString, fragStringStream.str().c_str());
1699 
1700     std::vector<GLBuffer> buffers(maxShaderStorageBuffers);
1701     for (GLint index = 0; index < maxShaderStorageBuffers; ++index)
1702     {
1703         glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[index]);
1704         glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), NULL, GL_STATIC_DRAW);
1705         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, buffers[index]);
1706     }
1707 
1708     glDrawArrays(GL_POINTS, 0, 6);
1709     ASSERT_GL_NO_ERROR();
1710 }
1711 
1712 // Test validation of redefinition of gl_Position and gl_PointSize in the vertex shader when
1713 // GL_EXT_separate_shader_objects is enabled.
TEST_P(ProgramPipelineTest31,ValidatePositionPointSizeRedefinition)1714 TEST_P(ProgramPipelineTest31, ValidatePositionPointSizeRedefinition)
1715 {
1716     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_separate_shader_objects"));
1717 
1718     {
1719         constexpr char kVS[] = R"(#version 310 es
1720 #extension GL_EXT_separate_shader_objects: require
1721 
1722 out float gl_PointSize;
1723 
1724 void main()
1725 {
1726     gl_Position = vec4(0);
1727     gl_PointSize = 1.;
1728 })";
1729 
1730         // Should fail because gl_Position is not declared.
1731         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
1732         EXPECT_EQ(shader, 0u);
1733     }
1734 
1735     {
1736         constexpr char kVS[] = R"(#version 310 es
1737 #extension GL_EXT_separate_shader_objects: require
1738 
1739 out float gl_PointSize;
1740 
1741 void f()
1742 {
1743     gl_PointSize = 1.;
1744 }
1745 
1746 out vec4 gl_Position;
1747 
1748 void main()
1749 {
1750     gl_Position = vec4(0);
1751 })";
1752 
1753         // Should fail because gl_PointSize is used before gl_Position is declared.
1754         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
1755         EXPECT_EQ(shader, 0u);
1756     }
1757 
1758     {
1759         constexpr char kVS[] = R"(#version 310 es
1760 #extension GL_EXT_separate_shader_objects: require
1761 
1762 out float gl_PointSize;
1763 out vec4 gl_Position;
1764 
1765 void main()
1766 {
1767     gl_Position = vec4(0);
1768     gl_PointSize = 1.;
1769 })";
1770 
1771         // Should compile.
1772         GLuint shader = createShaderProgram(GL_VERTEX_SHADER, kVS);
1773         EXPECT_NE(shader, 0u);
1774     }
1775 }
1776 
1777 // Basic draw test with GL_EXT_separate_shader_objects enabled in the vertex shader
TEST_P(ProgramPipelineTest31,BasicDrawWithPositionPointSizeRedefinition)1778 TEST_P(ProgramPipelineTest31, BasicDrawWithPositionPointSizeRedefinition)
1779 {
1780     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_separate_shader_objects"));
1781 
1782     const char kVS[] = R"(#version 310 es
1783 #extension GL_EXT_separate_shader_objects: require
1784 
1785 out float gl_PointSize;
1786 out vec4 gl_Position;
1787 
1788 in vec4 a_position;
1789 
1790 void main()
1791 {
1792     gl_Position = a_position;
1793 })";
1794 
1795     mVertProg = createShaderProgram(GL_VERTEX_SHADER, kVS);
1796     ASSERT_NE(mVertProg, 0u);
1797     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, essl31_shaders::fs::Red());
1798     ASSERT_NE(mFragProg, 0u);
1799 
1800     // Generate a program pipeline and attach the programs to their respective stages
1801     GLuint pipeline;
1802     glGenProgramPipelines(1, &pipeline);
1803     glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1804     glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1805     glBindProgramPipeline(pipeline);
1806     EXPECT_GL_NO_ERROR();
1807 
1808     drawQuadWithPPO("a_position", 0.5f, 1.0f);
1809     ASSERT_GL_NO_ERROR();
1810     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1811 }
1812 
1813 class ProgramPipelineTest32 : public ProgramPipelineTest
1814 {
1815   protected:
testTearDown()1816     void testTearDown() override
1817     {
1818         glDeleteProgram(mVertProg);
1819         glDeleteProgram(mFragProg);
1820         glDeleteProgramPipelines(1, &mPipeline);
1821     }
1822 
1823     void bindProgramPipeline(const GLchar *vertString,
1824                              const GLchar *fragString,
1825                              const GLchar *geomString);
1826     void drawQuadWithPPO(const std::string &positionAttribName,
1827                          const GLfloat positionAttribZ,
1828                          const GLfloat positionAttribXYScale);
1829 
1830     GLuint mVertProg = 0;
1831     GLuint mFragProg = 0;
1832     GLuint mGeomProg = 0;
1833     GLuint mPipeline = 0;
1834 };
1835 
bindProgramPipeline(const GLchar * vertString,const GLchar * fragString,const GLchar * geomString)1836 void ProgramPipelineTest32::bindProgramPipeline(const GLchar *vertString,
1837                                                 const GLchar *fragString,
1838                                                 const GLchar *geomString)
1839 {
1840     mVertProg = createShaderProgram(GL_VERTEX_SHADER, vertString);
1841     ASSERT_NE(mVertProg, 0u);
1842     mFragProg = createShaderProgram(GL_FRAGMENT_SHADER, fragString);
1843     ASSERT_NE(mFragProg, 0u);
1844     mGeomProg = createShaderProgram(GL_GEOMETRY_SHADER, geomString);
1845     ASSERT_NE(mGeomProg, 0u);
1846 
1847     // Generate a program pipeline and attach the programs to their respective stages
1848     glGenProgramPipelines(1, &mPipeline);
1849     EXPECT_GL_NO_ERROR();
1850     glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
1851     EXPECT_GL_NO_ERROR();
1852     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
1853     EXPECT_GL_NO_ERROR();
1854     glUseProgramStages(mPipeline, GL_GEOMETRY_SHADER_BIT, mGeomProg);
1855     EXPECT_GL_NO_ERROR();
1856     glBindProgramPipeline(mPipeline);
1857     EXPECT_GL_NO_ERROR();
1858 }
1859 
1860 // Verify that we can have the max amount of uniforms with a geometry shader as part of a program
1861 // pipeline.
TEST_P(ProgramPipelineTest32,MaxGeometryImageUniforms)1862 TEST_P(ProgramPipelineTest32, MaxGeometryImageUniforms)
1863 {
1864     ANGLE_SKIP_TEST_IF(!IsVulkan() || !IsGLExtensionEnabled("GL_EXT_geometry_shader"));
1865 
1866     GLint maxGeometryImageUnits;
1867     glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT, &maxGeometryImageUnits);
1868 
1869     const GLchar *vertString = essl31_shaders::vs::Simple();
1870     const GLchar *fragString = R"(#version 310 es
1871 precision highp float;
1872 out vec4 my_FragColor;
1873 void main()
1874 {
1875     my_FragColor = vec4(1.0);
1876 })";
1877 
1878     std::stringstream geomStringStream;
1879 
1880     geomStringStream << R"(#version 310 es
1881 #extension GL_OES_geometry_shader : require
1882 layout (points)                   in;
1883 layout (points, max_vertices = 1) out;
1884 
1885 precision highp iimage2D;
1886 
1887 ivec4 counter = ivec4(0);
1888 )";
1889 
1890     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
1891     {
1892         geomStringStream << "layout(binding = " << index << ", r32i) uniform iimage2D img" << index
1893                          << ";" << std::endl;
1894     }
1895 
1896     geomStringStream << R"(
1897 void main()
1898 {
1899 )";
1900 
1901     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
1902     {
1903         geomStringStream << "counter += imageLoad(img" << index << ", ivec2(0, 0));" << std::endl;
1904     }
1905 
1906     geomStringStream << R"(
1907     gl_Position = vec4(float(counter.x), 0.0, 0.0, 1.0);
1908     EmitVertex();
1909 }
1910 )";
1911 
1912     bindProgramPipeline(vertString, fragString, geomStringStream.str().c_str());
1913 
1914     std::vector<GLTexture> textures(maxGeometryImageUnits);
1915     for (GLint index = 0; index < maxGeometryImageUnits; ++index)
1916     {
1917         GLint value = index + 1;
1918 
1919         glBindTexture(GL_TEXTURE_2D, textures[index]);
1920         glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, 1, 1);
1921         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_INT, &value);
1922         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1923         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1924 
1925         glBindImageTexture(index, textures[index], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32I);
1926     }
1927 
1928     glDrawArrays(GL_POINTS, 0, 6);
1929     ASSERT_GL_NO_ERROR();
1930 }
1931 
1932 // Verify creation of seperable tessellation control shader program with transform feeback varying
TEST_P(ProgramPipelineTest32,CreateProgramWithTransformFeedbackVarying)1933 TEST_P(ProgramPipelineTest32, CreateProgramWithTransformFeedbackVarying)
1934 {
1935     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
1936 
1937     const char *kVS =
1938         "#version 320 es\n"
1939         "\n"
1940         "#extension GL_EXT_shader_io_blocks : require\n"
1941         "\n"
1942         "precision highp float;\n"
1943 
1944         "out BLOCK_INOUT { vec4 value; } user_out;\n"
1945         "\n"
1946         "void main()\n"
1947         "{\n"
1948         "    gl_Position    = vec4(1.0, 0.0, 0.0, 1.0);\n"
1949         "    user_out.value = vec4(4.0, 5.0, 6.0, 7.0);\n"
1950         "}\n";
1951 
1952     // Fragment shader body
1953     const char *kFS =
1954         "#version 320 es\n"
1955         "\n"
1956         "#extension GL_EXT_shader_io_blocks : require\n"
1957         "\n"
1958         "precision highp float;\n"
1959         "in BLOCK_INOUT { vec4 value; } user_in;\n"
1960         "\n"
1961         "void main()\n"
1962         "{\n"
1963         "}\n";
1964 
1965     // Geometry shader body
1966     const char *kGS =
1967         "#version 320 es\n"
1968         "\n"
1969         "#extension GL_EXT_geometry_shader : require\n"
1970         "\n"
1971         "layout(points)                   in;\n"
1972         "layout(points, max_vertices = 1) out;\n"
1973         "\n"
1974         "precision highp float;\n"
1975         "//${IN_PER_VERTEX_DECL_ARRAY}\n"
1976         "//${OUT_PER_VERTEX_DECL}\n"
1977         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
1978         "out BLOCK_INOUT { vec4 value; } user_out;\n"
1979         "\n"
1980         "void main()\n"
1981         "{\n"
1982         "    user_out.value = vec4(1.0, 2.0, 3.0, 4.0);\n"
1983         "    gl_Position    = vec4(0.0, 0.0, 0.0, 1.0);\n"
1984         "\n"
1985         "    EmitVertex();\n"
1986         "}\n";
1987 
1988     // tessellation control shader body
1989     const char *kTCS =
1990         "#version 320 es\n"
1991         "\n"
1992         "#extension GL_EXT_tessellation_shader : require\n"
1993         "#extension GL_EXT_shader_io_blocks : require\n"
1994         "\n"
1995         "layout (vertices=4) out;\n"
1996         "\n"
1997         "precision highp float;\n"
1998         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
1999         "out BLOCK_INOUT { vec4 value; } user_out[];\n"
2000         "\n"
2001         "void main()\n"
2002         "{\n"
2003         "    gl_out   [gl_InvocationID].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
2004         "    user_out [gl_InvocationID].value       = vec4(2.0, 3.0, 4.0, 5.0);\n"
2005         "\n"
2006         "    gl_TessLevelOuter[0] = 1.0;\n"
2007         "    gl_TessLevelOuter[1] = 1.0;\n"
2008         "}\n";
2009 
2010     // Tessellation evaluation shader
2011     const char *kTES =
2012         "#version 320 es\n"
2013         "\n"
2014         "#extension GL_EXT_tessellation_shader : require\n"
2015         "#extension GL_EXT_shader_io_blocks : require\n"
2016         "\n"
2017         "layout (isolines, point_mode) in;\n"
2018         "\n"
2019         "precision highp float;\n"
2020         "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
2021         "out BLOCK_INOUT { vec4 value; } user_out;\n"
2022         "\n"
2023         "void main()\n"
2024         "{\n"
2025         "    gl_Position     = gl_in[0].gl_Position;\n"
2026         "    user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n"
2027         "}\n";
2028     const GLchar *kVaryingName = "BLOCK_INOUT.value";
2029 
2030     GLuint fsProgram = createShaderProgram(GL_FRAGMENT_SHADER, kFS);
2031     ASSERT_NE(0u, fsProgram);
2032 
2033     GLuint vsProgram = createShaderProgram(GL_VERTEX_SHADER, kVS, 1, &kVaryingName);
2034     ASSERT_NE(0u, vsProgram);
2035 
2036     GLuint gsProgram = 0u;
2037     if (IsGLExtensionEnabled("GL_EXT_geometry_shader"))
2038     {
2039         gsProgram = createShaderProgram(GL_GEOMETRY_SHADER, kGS, 1, &kVaryingName);
2040         ASSERT_NE(0u, gsProgram);
2041     }
2042 
2043     GLuint tcsProgram = createShaderProgram(GL_TESS_CONTROL_SHADER, kTCS, 1, &kVaryingName);
2044     // Should fail here.
2045     ASSERT_EQ(0u, tcsProgram);
2046 
2047     // try compiling without transform feedback varying it should pass
2048     tcsProgram = createShaderProgram(GL_TESS_CONTROL_SHADER, kTCS);
2049     ASSERT_NE(0u, tcsProgram);
2050 
2051     GLuint tesProgram = createShaderProgram(GL_TESS_EVALUATION_SHADER, kTES, 1, &kVaryingName);
2052     ASSERT_NE(0u, tesProgram);
2053 
2054     glDeleteProgram(fsProgram);
2055     glDeleteProgram(vsProgram);
2056     if (gsProgram != 0u)
2057     {
2058         glDeleteProgram(gsProgram);
2059     }
2060     glDeleteProgram(tcsProgram);
2061     glDeleteProgram(tesProgram);
2062 }
2063 
2064 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest);
2065 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(ProgramPipelineTest);
2066 
2067 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest31);
2068 ANGLE_INSTANTIATE_TEST_ES31(ProgramPipelineTest31);
2069 
2070 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineXFBTest31);
2071 ANGLE_INSTANTIATE_TEST_ES31(ProgramPipelineXFBTest31);
2072 
2073 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest32);
2074 ANGLE_INSTANTIATE_TEST_ES32(ProgramPipelineTest32);
2075 
2076 }  // namespace
2077