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