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