1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Tests for separate shader objects
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fSeparateShaderTests.hpp"
25
26 #include "deInt32.h"
27 #include "deString.h"
28 #include "deStringUtil.hpp"
29 #include "deUniquePtr.hpp"
30 #include "deRandom.hpp"
31 #include "deSTLUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "tcuImageCompare.hpp"
34 #include "tcuRenderTarget.hpp"
35 #include "tcuResultCollector.hpp"
36 #include "tcuRGBA.hpp"
37 #include "tcuSurface.hpp"
38 #include "tcuStringTemplate.hpp"
39 #include "gluCallLogWrapper.hpp"
40 #include "gluPixelTransfer.hpp"
41 #include "gluRenderContext.hpp"
42 #include "gluShaderProgram.hpp"
43 #include "gluVarType.hpp"
44 #include "glsShaderLibrary.hpp"
45 #include "glwFunctions.hpp"
46 #include "glwDefs.hpp"
47 #include "glwEnums.hpp"
48
49 #include <cstdarg>
50 #include <algorithm>
51 #include <map>
52 #include <sstream>
53 #include <string>
54 #include <set>
55 #include <vector>
56
57 namespace deqp
58 {
59 namespace gles31
60 {
61 namespace Functional
62 {
63 namespace
64 {
65
66 using de::MovePtr;
67 using de::Random;
68 using de::UniquePtr;
69 using glu::CallLogWrapper;
70 using glu::DataType;
71 using glu::FragmentSource;
72 using glu::Precision;
73 using glu::Program;
74 using glu::ProgramPipeline;
75 using glu::ProgramSeparable;
76 using glu::ProgramSources;
77 using glu::RenderContext;
78 using glu::ShaderProgram;
79 using glu::ShaderType;
80 using glu::Storage;
81 using glu::VariableDeclaration;
82 using glu::VarType;
83 using glu::VertexSource;
84 using std::map;
85 using std::ostringstream;
86 using std::set;
87 using std::string;
88 using std::vector;
89 using tcu::MessageBuilder;
90 using tcu::RenderTarget;
91 using tcu::ResultCollector;
92 using tcu::StringTemplate;
93 using tcu::Surface;
94 using tcu::TestLog;
95
96 using namespace glw;
97
98 #define LOG_CALL(CALL) \
99 do \
100 { \
101 enableLogging(true); \
102 CALL; \
103 enableLogging(false); \
104 } while (false)
105
106 enum
107 {
108 VIEWPORT_SIZE = 128
109 };
110
111 enum VaryingInterpolation
112 {
113 VARYINGINTERPOLATION_SMOOTH = 0,
114 VARYINGINTERPOLATION_FLAT,
115 VARYINGINTERPOLATION_CENTROID,
116 VARYINGINTERPOLATION_DEFAULT,
117 VARYINGINTERPOLATION_RANDOM,
118
119 VARYINGINTERPOLATION_LAST
120 };
121
randomType(Random & rnd)122 DataType randomType(Random &rnd)
123 {
124 using namespace glu;
125
126 if (rnd.getInt(0, 7) == 0)
127 {
128 const int numCols = rnd.getInt(2, 4), numRows = rnd.getInt(2, 4);
129
130 return getDataTypeMatrix(numCols, numRows);
131 }
132 else
133 {
134 static const DataType s_types[] = {TYPE_FLOAT, TYPE_INT, TYPE_UINT};
135 static const float s_weights[] = {3.0, 1.0, 1.0};
136 const int size = rnd.getInt(1, 4);
137 const DataType scalarType =
138 rnd.chooseWeighted<DataType>(DE_ARRAY_BEGIN(s_types), DE_ARRAY_END(s_types), DE_ARRAY_BEGIN(s_weights));
139 return getDataTypeVector(scalarType, size);
140 }
141
142 DE_FATAL("Impossible");
143 return TYPE_INVALID;
144 }
145
randomInterpolation(Random & rnd)146 VaryingInterpolation randomInterpolation(Random &rnd)
147 {
148 static const VaryingInterpolation s_validInterpolations[] = {
149 VARYINGINTERPOLATION_SMOOTH,
150 VARYINGINTERPOLATION_FLAT,
151 VARYINGINTERPOLATION_CENTROID,
152 VARYINGINTERPOLATION_DEFAULT,
153 };
154 return s_validInterpolations[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_validInterpolations) - 1)];
155 }
156
getGluInterpolation(VaryingInterpolation interpolation)157 glu::Interpolation getGluInterpolation(VaryingInterpolation interpolation)
158 {
159 switch (interpolation)
160 {
161 case VARYINGINTERPOLATION_SMOOTH:
162 return glu::INTERPOLATION_SMOOTH;
163 case VARYINGINTERPOLATION_FLAT:
164 return glu::INTERPOLATION_FLAT;
165 case VARYINGINTERPOLATION_CENTROID:
166 return glu::INTERPOLATION_CENTROID;
167 case VARYINGINTERPOLATION_DEFAULT:
168 return glu::INTERPOLATION_LAST; //!< Last means no qualifier, i.e. default
169 default:
170 DE_FATAL("Invalid interpolation");
171 return glu::INTERPOLATION_LAST;
172 }
173 }
174
175 // used only for debug quick checks
176 #if defined(DE_DEBUG)
getVaryingInterpolation(glu::Interpolation interpolation)177 VaryingInterpolation getVaryingInterpolation(glu::Interpolation interpolation)
178 {
179 switch (interpolation)
180 {
181 case glu::INTERPOLATION_SMOOTH:
182 return VARYINGINTERPOLATION_SMOOTH;
183 case glu::INTERPOLATION_FLAT:
184 return VARYINGINTERPOLATION_FLAT;
185 case glu::INTERPOLATION_CENTROID:
186 return VARYINGINTERPOLATION_CENTROID;
187 case glu::INTERPOLATION_LAST:
188 return VARYINGINTERPOLATION_DEFAULT; //!< Last means no qualifier, i.e. default
189 default:
190 DE_FATAL("Invalid interpolation");
191 return VARYINGINTERPOLATION_LAST;
192 }
193 }
194 #endif
195
196 enum BindingKind
197 {
198 BINDING_NAME,
199 BINDING_LOCATION,
200 BINDING_LAST
201 };
202
randomBinding(Random & rnd)203 BindingKind randomBinding(Random &rnd)
204 {
205 return rnd.getBool() ? BINDING_LOCATION : BINDING_NAME;
206 }
207
printInputColor(ostringstream & oss,const VariableDeclaration & input)208 void printInputColor(ostringstream &oss, const VariableDeclaration &input)
209 {
210 using namespace glu;
211
212 const DataType basicType = input.varType.getBasicType();
213 string exp = input.name;
214
215 switch (getDataTypeScalarType(basicType))
216 {
217 case TYPE_FLOAT:
218 break;
219
220 case TYPE_INT:
221 case TYPE_UINT:
222 {
223 DataType floatType = getDataTypeFloatScalars(basicType);
224 exp = string() + "(" + getDataTypeName(floatType) + "(" + exp + ") / 255.0" + ")";
225 break;
226 }
227
228 default:
229 DE_FATAL("Impossible");
230 }
231
232 if (isDataTypeScalarOrVector(basicType))
233 {
234 switch (getDataTypeScalarSize(basicType))
235 {
236 case 1:
237 oss << "hsv(vec3(" << exp << ", 1.0, 1.0))";
238 break;
239 case 2:
240 oss << "hsv(vec3(" << exp << ", 1.0))";
241 break;
242 case 3:
243 oss << "vec4(" << exp << ", 1.0)";
244 break;
245 case 4:
246 oss << exp;
247 break;
248 default:
249 DE_FATAL("Impossible");
250 }
251 }
252 else if (isDataTypeMatrix(basicType))
253 {
254 int rows = getDataTypeMatrixNumRows(basicType);
255 int columns = getDataTypeMatrixNumColumns(basicType);
256
257 if (rows == columns)
258 oss << "hsv(vec3(determinant(" << exp << ")))";
259 else
260 {
261 if (rows != 3 && columns >= 3)
262 {
263 exp = "transpose(" + exp + ")";
264 std::swap(rows, columns);
265 }
266 exp = exp + "[0]";
267 if (rows > 3)
268 exp = exp + ".xyz";
269 oss << "hsv(" << exp << ")";
270 }
271 }
272 else
273 DE_FATAL("Impossible");
274 }
275
276 // Representation for the varyings between vertex and fragment shaders
277
278 struct VaryingParams
279 {
VaryingParamsdeqp::gles31::Functional::__anonf652bf1a0111::VaryingParams280 VaryingParams(void)
281 : count(0)
282 , type(glu::TYPE_LAST)
283 , binding(BINDING_LAST)
284 , vtxInterp(VARYINGINTERPOLATION_LAST)
285 , frgInterp(VARYINGINTERPOLATION_LAST)
286 {
287 }
288
289 int count;
290 DataType type;
291 BindingKind binding;
292 VaryingInterpolation vtxInterp;
293 VaryingInterpolation frgInterp;
294 };
295
296 struct VaryingInterface
297 {
298 vector<VariableDeclaration> vtxOutputs;
299 vector<VariableDeclaration> frgInputs;
300 };
301
302 // Generate corresponding input and output variable declarations that may vary
303 // in compatible ways.
304
chooseInterpolation(VaryingInterpolation param,DataType type,Random & rnd)305 VaryingInterpolation chooseInterpolation(VaryingInterpolation param, DataType type, Random &rnd)
306 {
307 if (glu::getDataTypeScalarType(type) != glu::TYPE_FLOAT)
308 return VARYINGINTERPOLATION_FLAT;
309
310 if (param == VARYINGINTERPOLATION_RANDOM)
311 return randomInterpolation(rnd);
312
313 return param;
314 }
315
isSSOCompatibleInterpolation(VaryingInterpolation vertexInterpolation,VaryingInterpolation fragmentInterpolation)316 bool isSSOCompatibleInterpolation(VaryingInterpolation vertexInterpolation, VaryingInterpolation fragmentInterpolation)
317 {
318 // interpolations must be fully specified
319 DE_ASSERT(vertexInterpolation != VARYINGINTERPOLATION_RANDOM);
320 DE_ASSERT(vertexInterpolation < VARYINGINTERPOLATION_LAST);
321 DE_ASSERT(fragmentInterpolation != VARYINGINTERPOLATION_RANDOM);
322 DE_ASSERT(fragmentInterpolation < VARYINGINTERPOLATION_LAST);
323
324 // interpolation can only be either smooth or flat. Auxiliary storage does not matter.
325 const bool isSmoothVtx =
326 (vertexInterpolation == VARYINGINTERPOLATION_SMOOTH) || //!< trivial
327 (vertexInterpolation == VARYINGINTERPOLATION_DEFAULT) || //!< default to smooth
328 (vertexInterpolation == VARYINGINTERPOLATION_CENTROID); //!< default to smooth, ignore storage
329 const bool isSmoothFrag =
330 (fragmentInterpolation == VARYINGINTERPOLATION_SMOOTH) || //!< trivial
331 (fragmentInterpolation == VARYINGINTERPOLATION_DEFAULT) || //!< default to smooth
332 (fragmentInterpolation == VARYINGINTERPOLATION_CENTROID); //!< default to smooth, ignore storage
333 // Khronos bug #12630: flat / smooth qualifiers must match in SSO
334 return isSmoothVtx == isSmoothFrag;
335 }
336
genVaryingInterface(const VaryingParams & params,Random & rnd)337 VaryingInterface genVaryingInterface(const VaryingParams ¶ms, Random &rnd)
338 {
339 using namespace glu;
340
341 VaryingInterface ret;
342 int offset = 0;
343
344 for (int varNdx = 0; varNdx < params.count; ++varNdx)
345 {
346 const BindingKind binding = ((params.binding == BINDING_LAST) ? randomBinding(rnd) : params.binding);
347 const DataType type = ((params.type == TYPE_LAST) ? randomType(rnd) : params.type);
348 const VaryingInterpolation vtxInterp = chooseInterpolation(params.vtxInterp, type, rnd);
349 const VaryingInterpolation frgInterp = chooseInterpolation(params.frgInterp, type, rnd);
350 const VaryingInterpolation vtxCompatInterp =
351 (isSSOCompatibleInterpolation(vtxInterp, frgInterp)) ? (vtxInterp) : (frgInterp);
352 const int loc = ((binding == BINDING_LOCATION) ? offset : -1);
353 const string ndxStr = de::toString(varNdx);
354 const string vtxName = ((binding == BINDING_NAME) ? "var" + ndxStr : "vtxVar" + ndxStr);
355 const string frgName = ((binding == BINDING_NAME) ? "var" + ndxStr : "frgVar" + ndxStr);
356 const VarType varType(type, PRECISION_HIGHP);
357
358 offset += getDataTypeNumLocations(type);
359
360 // Over 16 locations aren't necessarily supported, so halt here.
361 if (offset > 16)
362 break;
363
364 ret.vtxOutputs.push_back(
365 VariableDeclaration(varType, vtxName, STORAGE_OUT, getGluInterpolation(vtxCompatInterp), loc));
366 ret.frgInputs.push_back(VariableDeclaration(varType, frgName, STORAGE_IN, getGluInterpolation(frgInterp), loc));
367 }
368
369 return ret;
370 }
371
372 // Create vertex output variable declarations that are maximally compatible
373 // with the fragment input variables.
374
varyingCompatVtxOutputs(const VaryingInterface & varyings)375 vector<VariableDeclaration> varyingCompatVtxOutputs(const VaryingInterface &varyings)
376 {
377 vector<VariableDeclaration> outputs = varyings.vtxOutputs;
378
379 for (size_t i = 0; i < outputs.size(); ++i)
380 {
381 outputs[i].interpolation = varyings.frgInputs[i].interpolation;
382 outputs[i].name = varyings.frgInputs[i].name;
383 }
384
385 return outputs;
386 }
387
388 // Shader source generation
389
printFloat(ostringstream & oss,double d)390 void printFloat(ostringstream &oss, double d)
391 {
392 oss.setf(oss.fixed | oss.internal);
393 oss.precision(4);
394 oss.width(7);
395 oss << d;
396 }
397
printFloatDeclaration(ostringstream & oss,const string & varName,bool uniform,GLfloat value=0.0)398 void printFloatDeclaration(ostringstream &oss, const string &varName, bool uniform, GLfloat value = 0.0)
399 {
400 using namespace glu;
401
402 const VarType varType(TYPE_FLOAT, PRECISION_HIGHP);
403
404 if (uniform)
405 oss << VariableDeclaration(varType, varName, STORAGE_UNIFORM) << ";\n";
406 else
407 oss << VariableDeclaration(varType, varName, STORAGE_CONST) << " = " << de::floatToString(value, 6) << ";\n";
408 }
409
printRandomInitializer(ostringstream & oss,DataType type,Random & rnd)410 void printRandomInitializer(ostringstream &oss, DataType type, Random &rnd)
411 {
412 using namespace glu;
413 const int size = getDataTypeScalarSize(type);
414
415 if (size > 0)
416 oss << getDataTypeName(type) << "(";
417
418 for (int i = 0; i < size; ++i)
419 {
420 oss << (i == 0 ? "" : ", ");
421 switch (getDataTypeScalarType(type))
422 {
423 case TYPE_FLOAT:
424 printFloat(oss, rnd.getInt(0, 16) / 16.0);
425 break;
426
427 case TYPE_INT:
428 case TYPE_UINT:
429 oss << rnd.getInt(0, 255);
430 break;
431
432 case TYPE_BOOL:
433 oss << (rnd.getBool() ? "true" : "false");
434 break;
435
436 default:
437 DE_FATAL("Impossible");
438 }
439 }
440
441 if (size > 0)
442 oss << ")";
443 }
444
genVtxShaderSrc(uint32_t seed,const vector<VariableDeclaration> & outputs,const string & varName,bool uniform,float value=0.0)445 string genVtxShaderSrc(uint32_t seed, const vector<VariableDeclaration> &outputs, const string &varName, bool uniform,
446 float value = 0.0)
447 {
448 ostringstream oss;
449 Random rnd(seed);
450 enum
451 {
452 NUM_COMPONENTS = 2
453 };
454 static const int s_quadrants[][NUM_COMPONENTS] = {{1, 1}, {-1, 1}, {1, -1}};
455
456 oss << "#version 310 es\n";
457
458 printFloatDeclaration(oss, varName, uniform, value);
459
460 for (vector<VariableDeclaration>::const_iterator it = outputs.begin(); it != outputs.end(); ++it)
461 oss << *it << ";\n";
462
463 oss << "const vec2 triangle[3] = vec2[3](\n";
464
465 for (int vertexNdx = 0; vertexNdx < DE_LENGTH_OF_ARRAY(s_quadrants); ++vertexNdx)
466 {
467 oss << "\tvec2(";
468
469 for (int componentNdx = 0; componentNdx < NUM_COMPONENTS; ++componentNdx)
470 {
471 printFloat(oss, s_quadrants[vertexNdx][componentNdx] * rnd.getInt(4, 16) / 16.0);
472 oss << (componentNdx < 1 ? ", " : "");
473 }
474
475 oss << ")" << (vertexNdx < 2 ? "," : "") << "\n";
476 }
477 oss << ");\n";
478
479 for (vector<VariableDeclaration>::const_iterator it = outputs.begin(); it != outputs.end(); ++it)
480 {
481 const DataType type = it->varType.getBasicType();
482 const string typeName = glu::getDataTypeName(type);
483
484 oss << "const " << typeName << " " << it->name << "Inits[3] = " << typeName << "[3](\n";
485 for (int i = 0; i < 3; ++i)
486 {
487 oss << (i == 0 ? "\t" : ",\n\t");
488 printRandomInitializer(oss, type, rnd);
489 }
490 oss << ");\n";
491 }
492
493 oss << "void main (void)\n"
494 << "{\n"
495 << "\tgl_Position = vec4(" << varName << " * triangle[gl_VertexID], 0.0, 1.0);\n";
496
497 for (vector<VariableDeclaration>::const_iterator it = outputs.begin(); it != outputs.end(); ++it)
498 oss << "\t" << it->name << " = " << it->name << "Inits[gl_VertexID];\n";
499
500 oss << "}\n";
501
502 return oss.str();
503 }
504
genFrgShaderSrc(uint32_t seed,const vector<VariableDeclaration> & inputs,const string & varName,bool uniform,float value=0.0)505 string genFrgShaderSrc(uint32_t seed, const vector<VariableDeclaration> &inputs, const string &varName, bool uniform,
506 float value = 0.0)
507 {
508 Random rnd(seed);
509 ostringstream oss;
510
511 oss.precision(4);
512 oss.width(7);
513 oss << "#version 310 es\n";
514
515 oss << "precision highp float;\n";
516
517 oss << "out vec4 fragColor;\n";
518
519 printFloatDeclaration(oss, varName, uniform, value);
520
521 for (vector<VariableDeclaration>::const_iterator it = inputs.begin(); it != inputs.end(); ++it)
522 oss << *it << ";\n";
523
524 // glsl % isn't defined for negative numbers
525 oss << "int imod (int n, int d)"
526 << "\n"
527 << "{"
528 << "\n"
529 << "\t"
530 << "return (n < 0 ? d - 1 - (-1 - n) % d : n % d);"
531 << "\n"
532 << "}"
533 << "\n";
534
535 oss << "vec4 hsv (vec3 hsv)"
536 << "{"
537 << "\n"
538 << "\tfloat h = hsv.x * 3.0;\n"
539 << "\tfloat r = max(0.0, 1.0 - h) + max(0.0, h - 2.0);\n"
540 << "\tfloat g = max(0.0, 1.0 - abs(h - 1.0));\n"
541 << "\tfloat b = max(0.0, 1.0 - abs(h - 2.0));\n"
542 << "\tvec3 hs = mix(vec3(1.0), vec3(r, g, b), hsv.y);\n"
543 << "\treturn vec4(hsv.z * hs, 1.0);\n"
544 << "}\n";
545
546 oss << "void main (void)\n"
547 << "{\n";
548
549 oss << "\t"
550 << "fragColor = vec4(vec3(" << varName << "), 1.0);"
551 << "\n";
552
553 if (inputs.size() > 0)
554 {
555 oss << "\t"
556 << "switch (imod(int(0.5 * (";
557
558 printFloat(oss, rnd.getFloat(0.5f, 2.0f));
559 oss << " * gl_FragCoord.x - ";
560
561 printFloat(oss, rnd.getFloat(0.5f, 2.0f));
562 oss << " * gl_FragCoord.y)), " << inputs.size() << "))"
563 << "\n"
564 << "\t"
565 << "{"
566 << "\n";
567
568 for (size_t i = 0; i < inputs.size(); ++i)
569 {
570 oss << "\t\t"
571 << "case " << i << ":"
572 << "\n"
573 << "\t\t\t"
574 << "fragColor *= ";
575
576 printInputColor(oss, inputs[i]);
577
578 oss << ";"
579 << "\n"
580 << "\t\t\t"
581 << "break;"
582 << "\n";
583 }
584
585 oss << "\t\t"
586 << "case " << inputs.size() << ":\n"
587 << "\t\t\t"
588 << "fragColor = vec4(1.0, 0.0, 1.0, 1.0);"
589 << "\n";
590 oss << "\t\t\t"
591 << "break;"
592 << "\n";
593
594 oss << "\t\t"
595 << "case -1:\n"
596 << "\t\t\t"
597 << "fragColor = vec4(1.0, 1.0, 0.0, 1.0);"
598 << "\n";
599 oss << "\t\t\t"
600 << "break;"
601 << "\n";
602
603 oss << "\t\t"
604 << "default:"
605 << "\n"
606 << "\t\t\t"
607 << "fragColor = vec4(1.0, 1.0, 0.0, 1.0);"
608 << "\n";
609
610 oss << "\t"
611 << "}\n";
612 }
613
614 oss << "}\n";
615
616 return oss.str();
617 }
618
619 // ProgramWrapper
620
621 class ProgramWrapper
622 {
623 public:
~ProgramWrapper(void)624 virtual ~ProgramWrapper(void)
625 {
626 }
627
628 virtual GLuint getProgramName(void) = 0;
629 virtual void writeToLog(TestLog &log) = 0;
630 };
631
632 class ShaderProgramWrapper : public ProgramWrapper
633 {
634 public:
ShaderProgramWrapper(const RenderContext & renderCtx,const ProgramSources & sources)635 ShaderProgramWrapper(const RenderContext &renderCtx, const ProgramSources &sources)
636 : m_shaderProgram(renderCtx, sources)
637 {
638 }
~ShaderProgramWrapper(void)639 ~ShaderProgramWrapper(void)
640 {
641 }
642
getProgramName(void)643 GLuint getProgramName(void)
644 {
645 return m_shaderProgram.getProgram();
646 }
getShaderProgram(void)647 ShaderProgram &getShaderProgram(void)
648 {
649 return m_shaderProgram;
650 }
writeToLog(TestLog & log)651 void writeToLog(TestLog &log)
652 {
653 log << m_shaderProgram;
654 }
655
656 private:
657 ShaderProgram m_shaderProgram;
658 };
659
660 class RawProgramWrapper : public ProgramWrapper
661 {
662 public:
RawProgramWrapper(const RenderContext & renderCtx,GLuint programName,ShaderType shaderType,const string & source)663 RawProgramWrapper(const RenderContext &renderCtx, GLuint programName, ShaderType shaderType, const string &source)
664 : m_program(renderCtx, programName)
665 , m_shaderType(shaderType)
666 , m_source(source)
667 {
668 }
~RawProgramWrapper(void)669 ~RawProgramWrapper(void)
670 {
671 }
672
getProgramName(void)673 GLuint getProgramName(void)
674 {
675 return m_program.getProgram();
676 }
getProgram(void)677 Program &getProgram(void)
678 {
679 return m_program;
680 }
681 void writeToLog(TestLog &log);
682
683 private:
684 Program m_program;
685 ShaderType m_shaderType;
686 const string m_source;
687 };
688
writeToLog(TestLog & log)689 void RawProgramWrapper::writeToLog(TestLog &log)
690 {
691 const string info = m_program.getInfoLog();
692 qpShaderType qpType = glu::getLogShaderType(m_shaderType);
693
694 log << TestLog::ShaderProgram(true, info)
695 << TestLog::Shader(qpType, m_source, true, "[Shader created by glCreateShaderProgramv()]")
696 << TestLog::EndShaderProgram;
697 }
698
699 // ProgramParams
700
701 struct ProgramParams
702 {
ProgramParamsdeqp::gles31::Functional::__anonf652bf1a0111::ProgramParams703 ProgramParams(uint32_t vtxSeed_, GLfloat vtxScale_, uint32_t frgSeed_, GLfloat frgScale_)
704 : vtxSeed(vtxSeed_)
705 , vtxScale(vtxScale_)
706 , frgSeed(frgSeed_)
707 , frgScale(frgScale_)
708 {
709 }
710 uint32_t vtxSeed;
711 GLfloat vtxScale;
712 uint32_t frgSeed;
713 GLfloat frgScale;
714 };
715
genProgramParams(Random & rnd)716 ProgramParams genProgramParams(Random &rnd)
717 {
718 const uint32_t vtxSeed = rnd.getUint32();
719 const GLfloat vtxScale = (float)rnd.getInt(8, 16) / 16.0f;
720 const uint32_t frgSeed = rnd.getUint32();
721 const GLfloat frgScale = (float)rnd.getInt(0, 16) / 16.0f;
722
723 return ProgramParams(vtxSeed, vtxScale, frgSeed, frgScale);
724 }
725
726 // TestParams
727
728 struct TestParams
729 {
730 bool initSingle;
731 bool switchVtx;
732 bool switchFrg;
733 bool useUniform;
734 bool useSameName;
735 bool useCreateHelper;
736 bool useProgramUniform;
737 VaryingParams varyings;
738 };
739
paramsSeed(const TestParams & params)740 uint32_t paramsSeed(const TestParams ¶ms)
741 {
742 uint32_t paramCode =
743 (params.initSingle << 0 | params.switchVtx << 1 | params.switchFrg << 2 | params.useUniform << 3 |
744 params.useSameName << 4 | params.useCreateHelper << 5 | params.useProgramUniform << 6);
745
746 paramCode = deUint32Hash(paramCode) + params.varyings.count;
747 paramCode = deUint32Hash(paramCode) + params.varyings.type;
748 paramCode = deUint32Hash(paramCode) + params.varyings.binding;
749 paramCode = deUint32Hash(paramCode) + params.varyings.vtxInterp;
750 paramCode = deUint32Hash(paramCode) + params.varyings.frgInterp;
751
752 return deUint32Hash(paramCode);
753 }
754
paramsCode(const TestParams & params)755 string paramsCode(const TestParams ¶ms)
756 {
757 using namespace glu;
758
759 ostringstream oss;
760
761 oss << (params.initSingle ? "1" : "2") << (params.switchVtx ? "v" : "") << (params.switchFrg ? "f" : "")
762 << (params.useProgramUniform ? "p" : "") << (params.useUniform ? "u" : "") << (params.useSameName ? "s" : "")
763 << (params.useCreateHelper ? "c" : "") << de::toString(params.varyings.count)
764 << (params.varyings.binding == BINDING_NAME ? "n" :
765 params.varyings.binding == BINDING_LOCATION ? "l" :
766 params.varyings.binding == BINDING_LAST ? "r" :
767 "")
768 << (params.varyings.vtxInterp == VARYINGINTERPOLATION_SMOOTH ? "m" :
769 params.varyings.vtxInterp == VARYINGINTERPOLATION_CENTROID ? "e" :
770 params.varyings.vtxInterp == VARYINGINTERPOLATION_FLAT ? "a" :
771 params.varyings.vtxInterp == VARYINGINTERPOLATION_RANDOM ? "r" :
772 "o")
773 << (params.varyings.frgInterp == VARYINGINTERPOLATION_SMOOTH ? "m" :
774 params.varyings.frgInterp == VARYINGINTERPOLATION_CENTROID ? "e" :
775 params.varyings.frgInterp == VARYINGINTERPOLATION_FLAT ? "a" :
776 params.varyings.frgInterp == VARYINGINTERPOLATION_RANDOM ? "r" :
777 "o");
778 return oss.str();
779 }
780
paramsValid(const TestParams & params)781 bool paramsValid(const TestParams ¶ms)
782 {
783 using namespace glu;
784
785 // Final pipeline has a single program?
786 if (params.initSingle)
787 {
788 // Cannot have conflicting names for uniforms or constants
789 if (params.useSameName)
790 return false;
791
792 // CreateShaderProgram would never get called
793 if (!params.switchVtx && !params.switchFrg && params.useCreateHelper)
794 return false;
795
796 // Must switch either all or nothing
797 if (params.switchVtx != params.switchFrg)
798 return false;
799 }
800
801 // ProgramUniform would never get called
802 if (params.useProgramUniform && !params.useUniform)
803 return false;
804
805 // Interpolation is meaningless if we don't use an in/out variable.
806 if (params.varyings.count == 0 && !(params.varyings.vtxInterp == VARYINGINTERPOLATION_LAST &&
807 params.varyings.frgInterp == VARYINGINTERPOLATION_LAST))
808 return false;
809
810 // Mismatch by flat / smooth is not allowed. See Khronos bug #12630
811 // \note: iterpolations might be RANDOM, causing generated varyings potentially match / mismatch anyway.
812 // This is checked later on. Here, we just make sure that we don't force the generator to generate
813 // only invalid varying configurations, i.e. there exists a valid varying configuration for this
814 // test param config.
815 if ((params.varyings.vtxInterp != VARYINGINTERPOLATION_RANDOM) &&
816 (params.varyings.frgInterp != VARYINGINTERPOLATION_RANDOM) &&
817 (params.varyings.vtxInterp == VARYINGINTERPOLATION_FLAT) !=
818 (params.varyings.frgInterp == VARYINGINTERPOLATION_FLAT))
819 return false;
820
821 return true;
822 }
823
824 // used only for debug quick checks
825 #if defined(DE_DEBUG)
varyingsValid(const VaryingInterface & varyings)826 bool varyingsValid(const VaryingInterface &varyings)
827 {
828 for (int ndx = 0; ndx < (int)varyings.vtxOutputs.size(); ++ndx)
829 {
830 const VaryingInterpolation vertexInterpolation =
831 getVaryingInterpolation(varyings.vtxOutputs[ndx].interpolation);
832 const VaryingInterpolation fragmentInterpolation =
833 getVaryingInterpolation(varyings.frgInputs[ndx].interpolation);
834
835 if (!isSSOCompatibleInterpolation(vertexInterpolation, fragmentInterpolation))
836 return false;
837 }
838
839 return true;
840 }
841 #endif
842
logParams(TestLog & log,const TestParams & params)843 void logParams(TestLog &log, const TestParams ¶ms)
844 {
845 // We don't log operational details here since those are shown
846 // in the log messages during execution.
847 MessageBuilder msg = log.message();
848
849 msg << "Pipeline configuration:\n";
850
851 msg << "Vertex and fragment shaders have " << (params.useUniform ? "uniform" : "constant") << "s with "
852 << (params.useSameName ? "the same name" : "different names") << ".\n";
853
854 if (params.varyings.count == 0)
855 msg << "There are no varyings.\n";
856 else
857 {
858 if (params.varyings.count == 1)
859 msg << "There is one varying.\n";
860 else
861 msg << "There are " << params.varyings.count << " varyings.\n";
862
863 if (params.varyings.type == glu::TYPE_LAST)
864 msg << "Varyings are of random types.\n";
865 else
866 msg << "Varyings are of type '" << glu::getDataTypeName(params.varyings.type) << "'.\n";
867
868 msg << "Varying outputs and inputs correspond ";
869 switch (params.varyings.binding)
870 {
871 case BINDING_NAME:
872 msg << "by name.\n";
873 break;
874 case BINDING_LOCATION:
875 msg << "by location.\n";
876 break;
877 case BINDING_LAST:
878 msg << "randomly either by name or by location.\n";
879 break;
880 default:
881 DE_FATAL("Impossible");
882 }
883
884 msg << "In the vertex shader the varyings are qualified ";
885 if (params.varyings.vtxInterp == VARYINGINTERPOLATION_DEFAULT)
886 msg << "with no interpolation qualifiers.\n";
887 else if (params.varyings.vtxInterp == VARYINGINTERPOLATION_RANDOM)
888 msg << "with a random interpolation qualifier.\n";
889 else
890 msg << "'" << glu::getInterpolationName(getGluInterpolation(params.varyings.vtxInterp)) << "'.\n";
891
892 msg << "In the fragment shader the varyings are qualified ";
893 if (params.varyings.frgInterp == VARYINGINTERPOLATION_DEFAULT)
894 msg << "with no interpolation qualifiers.\n";
895 else if (params.varyings.frgInterp == VARYINGINTERPOLATION_RANDOM)
896 msg << "with a random interpolation qualifier.\n";
897 else
898 msg << "'" << glu::getInterpolationName(getGluInterpolation(params.varyings.frgInterp)) << "'.\n";
899 }
900
901 msg << TestLog::EndMessage;
902
903 log.writeMessage("");
904 }
905
genParams(uint32_t seed)906 TestParams genParams(uint32_t seed)
907 {
908 Random rnd(seed);
909 TestParams params;
910 int tryNdx = 0;
911
912 do
913 {
914 params.initSingle = rnd.getBool();
915 params.switchVtx = rnd.getBool();
916 params.switchFrg = rnd.getBool();
917 params.useUniform = rnd.getBool();
918 params.useProgramUniform = params.useUniform && rnd.getBool();
919 params.useCreateHelper = rnd.getBool();
920 params.useSameName = rnd.getBool();
921 {
922 int i = rnd.getInt(-1, 3);
923 params.varyings.count = (i == -1 ? 0 : 1 << i);
924 }
925 if (params.varyings.count > 0)
926 {
927 params.varyings.type = glu::TYPE_LAST;
928 params.varyings.binding = BINDING_LAST;
929 params.varyings.vtxInterp = VARYINGINTERPOLATION_RANDOM;
930 params.varyings.frgInterp = VARYINGINTERPOLATION_RANDOM;
931 }
932 else
933 {
934 params.varyings.type = glu::TYPE_INVALID;
935 params.varyings.binding = BINDING_LAST;
936 params.varyings.vtxInterp = VARYINGINTERPOLATION_LAST;
937 params.varyings.frgInterp = VARYINGINTERPOLATION_LAST;
938 }
939
940 tryNdx += 1;
941 } while (!paramsValid(params) && tryNdx < 16);
942
943 DE_ASSERT(paramsValid(params));
944
945 return params;
946 }
947
948 // Program pipeline wrapper that retains references to component programs.
949
950 struct Pipeline
951 {
Pipelinedeqp::gles31::Functional::__anonf652bf1a0111::Pipeline952 Pipeline(MovePtr<ProgramPipeline> pipeline_, MovePtr<ProgramWrapper> fullProg_, MovePtr<ProgramWrapper> vtxProg_,
953 MovePtr<ProgramWrapper> frgProg_)
954 : pipeline(pipeline_)
955 , fullProg(fullProg_)
956 , vtxProg(vtxProg_)
957 , frgProg(frgProg_)
958 {
959 }
960
getVertexProgramdeqp::gles31::Functional::__anonf652bf1a0111::Pipeline961 ProgramWrapper &getVertexProgram(void) const
962 {
963 return vtxProg ? *vtxProg : *fullProg;
964 }
965
getFragmentProgramdeqp::gles31::Functional::__anonf652bf1a0111::Pipeline966 ProgramWrapper &getFragmentProgram(void) const
967 {
968 return frgProg ? *frgProg : *fullProg;
969 }
970
971 UniquePtr<ProgramPipeline> pipeline;
972 UniquePtr<ProgramWrapper> fullProg;
973 UniquePtr<ProgramWrapper> vtxProg;
974 UniquePtr<ProgramWrapper> frgProg;
975 };
976
logPipeline(TestLog & log,const Pipeline & pipeline)977 void logPipeline(TestLog &log, const Pipeline &pipeline)
978 {
979 ProgramWrapper &vtxProg = pipeline.getVertexProgram();
980 ProgramWrapper &frgProg = pipeline.getFragmentProgram();
981
982 log.writeMessage("// Failed program pipeline:");
983 if (&vtxProg == &frgProg)
984 {
985 log.writeMessage("// Common program for both vertex and fragment stages:");
986 vtxProg.writeToLog(log);
987 }
988 else
989 {
990 log.writeMessage("// Vertex stage program:");
991 vtxProg.writeToLog(log);
992 log.writeMessage("// Fragment stage program:");
993 frgProg.writeToLog(log);
994 }
995 }
996
997 // Rectangle
998
999 struct Rectangle
1000 {
Rectangledeqp::gles31::Functional::__anonf652bf1a0111::Rectangle1001 Rectangle(int x_, int y_, int width_, int height_) : x(x_), y(y_), width(width_), height(height_)
1002 {
1003 }
1004 int x;
1005 int y;
1006 int width;
1007 int height;
1008 };
1009
setViewport(const RenderContext & renderCtx,const Rectangle & rect)1010 void setViewport(const RenderContext &renderCtx, const Rectangle &rect)
1011 {
1012 renderCtx.getFunctions().viewport(rect.x, rect.y, rect.width, rect.height);
1013 }
1014
readRectangle(const RenderContext & renderCtx,const Rectangle & rect,Surface & dst)1015 void readRectangle(const RenderContext &renderCtx, const Rectangle &rect, Surface &dst)
1016 {
1017 dst.setSize(rect.width, rect.height);
1018 glu::readPixels(renderCtx, rect.x, rect.y, dst.getAccess());
1019 }
1020
randomViewport(const RenderContext & ctx,Random & rnd,GLint maxWidth,GLint maxHeight)1021 Rectangle randomViewport(const RenderContext &ctx, Random &rnd, GLint maxWidth, GLint maxHeight)
1022 {
1023 const RenderTarget &target = ctx.getRenderTarget();
1024 GLint width = de::min(target.getWidth(), maxWidth);
1025 GLint xOff = rnd.getInt(0, target.getWidth() - width);
1026 GLint height = de::min(target.getHeight(), maxHeight);
1027 GLint yOff = rnd.getInt(0, target.getHeight() - height);
1028
1029 return Rectangle(xOff, yOff, width, height);
1030 }
1031
1032 // SeparateShaderTest
1033
1034 class SeparateShaderTest : public TestCase, private CallLogWrapper
1035 {
1036 public:
1037 typedef void (SeparateShaderTest::*TestFunc)(MovePtr<Pipeline> &pipeOut);
1038
1039 SeparateShaderTest(Context &ctx, const string &name, const string &description, int iterations,
1040 const TestParams ¶ms, TestFunc testFunc);
1041
1042 IterateResult iterate(void);
1043
1044 void testPipelineRendering(MovePtr<Pipeline> &pipeOut);
1045 void testCurrentProgPriority(MovePtr<Pipeline> &pipeOut);
1046 void testActiveProgramUniform(MovePtr<Pipeline> &pipeOut);
1047 void testPipelineQueryActive(MovePtr<Pipeline> &pipeOut);
1048 void testPipelineQueryPrograms(MovePtr<Pipeline> &pipeOut);
1049
1050 private:
1051 TestLog &log(void);
1052 const RenderContext &getRenderContext(void);
1053
1054 void setUniform(ProgramWrapper &program, const string &uniformName, GLfloat value, bool useProgramUni);
1055
1056 void drawSurface(Surface &dst, uint32_t seed = 0);
1057
1058 MovePtr<ProgramWrapper> createShaderProgram(const string *vtxSource, const string *frgSource, bool separable);
1059
1060 MovePtr<ProgramWrapper> createSingleShaderProgram(ShaderType shaderType, const string &src);
1061
1062 MovePtr<Pipeline> createPipeline(const ProgramParams &pp);
1063
1064 MovePtr<ProgramWrapper> createReferenceProgram(const ProgramParams &pp);
1065
1066 int m_iterations;
1067 int m_currentIteration;
1068 TestParams m_params;
1069 TestFunc m_testFunc;
1070 Random m_rnd;
1071 ResultCollector m_status;
1072 VaryingInterface m_varyings;
1073
1074 // Per-iteration state required for logging on exception
1075 MovePtr<ProgramWrapper> m_fullProg;
1076 MovePtr<ProgramWrapper> m_vtxProg;
1077 MovePtr<ProgramWrapper> m_frgProg;
1078 };
1079
getRenderContext(void)1080 const RenderContext &SeparateShaderTest::getRenderContext(void)
1081 {
1082 return m_context.getRenderContext();
1083 }
1084
log(void)1085 TestLog &SeparateShaderTest::log(void)
1086 {
1087 return m_testCtx.getLog();
1088 }
1089
SeparateShaderTest(Context & ctx,const string & name,const string & description,int iterations,const TestParams & params,TestFunc testFunc)1090 SeparateShaderTest::SeparateShaderTest(Context &ctx, const string &name, const string &description, int iterations,
1091 const TestParams ¶ms, TestFunc testFunc)
1092 : TestCase(ctx, name.c_str(), description.c_str())
1093 , CallLogWrapper(ctx.getRenderContext().getFunctions(), log())
1094 , m_iterations(iterations)
1095 , m_currentIteration(0)
1096 , m_params(params)
1097 , m_testFunc(testFunc)
1098 , m_rnd(paramsSeed(params))
1099 , m_status(log(), "// ")
1100 , m_varyings(genVaryingInterface(params.varyings, m_rnd))
1101 {
1102 DE_ASSERT(paramsValid(params));
1103 DE_ASSERT(varyingsValid(m_varyings));
1104 }
1105
createShaderProgram(const string * vtxSource,const string * frgSource,bool separable)1106 MovePtr<ProgramWrapper> SeparateShaderTest::createShaderProgram(const string *vtxSource, const string *frgSource,
1107 bool separable)
1108 {
1109 ProgramSources sources;
1110
1111 if (vtxSource != DE_NULL)
1112 sources << VertexSource(*vtxSource);
1113 if (frgSource != DE_NULL)
1114 sources << FragmentSource(*frgSource);
1115 sources << ProgramSeparable(separable);
1116
1117 MovePtr<ShaderProgramWrapper> wrapper(new ShaderProgramWrapper(getRenderContext(), sources));
1118 if (!wrapper->getShaderProgram().isOk())
1119 {
1120 log().writeMessage("Couldn't create shader program");
1121 wrapper->writeToLog(log());
1122 TCU_FAIL("Couldn't create shader program");
1123 }
1124
1125 return MovePtr<ProgramWrapper>(wrapper.release());
1126 }
1127
createSingleShaderProgram(ShaderType shaderType,const string & src)1128 MovePtr<ProgramWrapper> SeparateShaderTest::createSingleShaderProgram(ShaderType shaderType, const string &src)
1129 {
1130 const RenderContext &renderCtx = getRenderContext();
1131
1132 if (m_params.useCreateHelper)
1133 {
1134 const char *const srcStr = src.c_str();
1135 const GLenum glType = glu::getGLShaderType(shaderType);
1136 const GLuint programName = glCreateShaderProgramv(glType, 1, &srcStr);
1137
1138 if (glGetError() != GL_NO_ERROR || programName == 0)
1139 {
1140 qpShaderType qpType = glu::getLogShaderType(shaderType);
1141
1142 log() << TestLog::Message << "glCreateShaderProgramv() failed" << TestLog::EndMessage
1143 << TestLog::ShaderProgram(false, "[glCreateShaderProgramv() failed]")
1144 << TestLog::Shader(qpType, src, false, "[glCreateShaderProgramv() failed]")
1145 << TestLog::EndShaderProgram;
1146 TCU_FAIL("glCreateShaderProgramv() failed");
1147 }
1148
1149 RawProgramWrapper *const wrapper = new RawProgramWrapper(renderCtx, programName, shaderType, src);
1150 MovePtr<ProgramWrapper> wrapperPtr(wrapper);
1151 Program &program = wrapper->getProgram();
1152
1153 if (!program.getLinkStatus())
1154 {
1155 log().writeMessage("glCreateShaderProgramv() failed at linking");
1156 wrapper->writeToLog(log());
1157 TCU_FAIL("glCreateShaderProgram() failed at linking");
1158 }
1159 return wrapperPtr;
1160 }
1161 else
1162 {
1163 switch (shaderType)
1164 {
1165 case glu::SHADERTYPE_VERTEX:
1166 return createShaderProgram(&src, DE_NULL, true);
1167 case glu::SHADERTYPE_FRAGMENT:
1168 return createShaderProgram(DE_NULL, &src, true);
1169 default:
1170 DE_FATAL("Impossible case");
1171 }
1172 }
1173 return MovePtr<ProgramWrapper>(); // Shut up compiler warnings.
1174 }
1175
setUniform(ProgramWrapper & program,const string & uniformName,GLfloat value,bool useProgramUniform)1176 void SeparateShaderTest::setUniform(ProgramWrapper &program, const string &uniformName, GLfloat value,
1177 bool useProgramUniform)
1178 {
1179 const GLuint progName = program.getProgramName();
1180 const GLint location = glGetUniformLocation(progName, uniformName.c_str());
1181 MessageBuilder msg = log().message();
1182
1183 msg << "// Set program " << progName << "'s uniform '" << uniformName << "' to " << value;
1184 if (useProgramUniform)
1185 {
1186 msg << " using glProgramUniform1f";
1187 glProgramUniform1f(progName, location, value);
1188 }
1189 else
1190 {
1191 msg << " using glUseProgram and glUniform1f";
1192 glUseProgram(progName);
1193 glUniform1f(location, value);
1194 glUseProgram(0);
1195 }
1196 msg << TestLog::EndMessage;
1197 }
1198
createPipeline(const ProgramParams & pp)1199 MovePtr<Pipeline> SeparateShaderTest::createPipeline(const ProgramParams &pp)
1200 {
1201 const bool useUniform = m_params.useUniform;
1202 const string vtxName = m_params.useSameName ? "scale" : "vtxScale";
1203 const uint32_t initVtxSeed = m_params.switchVtx ? m_rnd.getUint32() : pp.vtxSeed;
1204
1205 const string frgName = m_params.useSameName ? "scale" : "frgScale";
1206 const uint32_t initFrgSeed = m_params.switchFrg ? m_rnd.getUint32() : pp.frgSeed;
1207 const string frgSource = genFrgShaderSrc(initFrgSeed, m_varyings.frgInputs, frgName, useUniform, pp.frgScale);
1208
1209 const RenderContext &renderCtx = getRenderContext();
1210 MovePtr<ProgramPipeline> pipeline(new ProgramPipeline(renderCtx));
1211 MovePtr<ProgramWrapper> fullProg;
1212 MovePtr<ProgramWrapper> vtxProg;
1213 MovePtr<ProgramWrapper> frgProg;
1214
1215 // We cannot allow a situation where we have a single program with a
1216 // single uniform, because then the vertex and fragment shader uniforms
1217 // would not be distinct in the final pipeline, and we are going to test
1218 // that altering one uniform will not affect the other.
1219 DE_ASSERT(!(m_params.initSingle && m_params.useSameName && !m_params.switchVtx && !m_params.switchFrg));
1220
1221 if (m_params.initSingle)
1222 {
1223 string vtxSource =
1224 genVtxShaderSrc(initVtxSeed, varyingCompatVtxOutputs(m_varyings), vtxName, useUniform, pp.vtxScale);
1225 fullProg = createShaderProgram(&vtxSource, &frgSource, true);
1226 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, fullProg->getProgramName());
1227 log() << TestLog::Message << "// Created pipeline " << pipeline->getPipeline() << " with two-shader program "
1228 << fullProg->getProgramName() << TestLog::EndMessage;
1229 }
1230 else
1231 {
1232 string vtxSource = genVtxShaderSrc(initVtxSeed, m_varyings.vtxOutputs, vtxName, useUniform, pp.vtxScale);
1233 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, vtxSource);
1234 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1235
1236 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, frgSource);
1237 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1238
1239 log() << TestLog::Message << "// Created pipeline " << pipeline->getPipeline() << " with vertex program "
1240 << vtxProg->getProgramName() << " and fragment program " << frgProg->getProgramName()
1241 << TestLog::EndMessage;
1242 }
1243
1244 m_status.check(pipeline->isValid(), "Pipeline is invalid after initialization");
1245
1246 if (m_params.switchVtx)
1247 {
1248 string newSource = genVtxShaderSrc(pp.vtxSeed, m_varyings.vtxOutputs, vtxName, useUniform, pp.vtxScale);
1249 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, newSource);
1250 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1251 log() << TestLog::Message << "// Switched pipeline " << pipeline->getPipeline()
1252 << "'s vertex stage to single-shader program " << vtxProg->getProgramName() << TestLog::EndMessage;
1253 }
1254 if (m_params.switchFrg)
1255 {
1256 string newSource = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs, frgName, useUniform, pp.frgScale);
1257 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, newSource);
1258 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1259 log() << TestLog::Message << "// Switched pipeline " << pipeline->getPipeline()
1260 << "'s fragment stage to single-shader program " << frgProg->getProgramName() << TestLog::EndMessage;
1261 }
1262
1263 if (m_params.switchVtx || m_params.switchFrg)
1264 m_status.check(pipeline->isValid(), "Pipeline became invalid after changing a stage's program");
1265
1266 if (m_params.useUniform)
1267 {
1268 ProgramWrapper &vtxStage = *(vtxProg ? vtxProg : fullProg);
1269 ProgramWrapper &frgStage = *(frgProg ? frgProg : fullProg);
1270
1271 setUniform(vtxStage, vtxName, pp.vtxScale, m_params.useProgramUniform);
1272 setUniform(frgStage, frgName, pp.frgScale, m_params.useProgramUniform);
1273 }
1274 else
1275 log().writeMessage("// Programs use constants instead of uniforms");
1276
1277 return MovePtr<Pipeline>(new Pipeline(pipeline, fullProg, vtxProg, frgProg));
1278 }
1279
createReferenceProgram(const ProgramParams & pp)1280 MovePtr<ProgramWrapper> SeparateShaderTest::createReferenceProgram(const ProgramParams &pp)
1281 {
1282 bool useUniform = m_params.useUniform;
1283 const string vtxSrc =
1284 genVtxShaderSrc(pp.vtxSeed, varyingCompatVtxOutputs(m_varyings), "vtxScale", useUniform, pp.vtxScale);
1285 const string frgSrc = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs, "frgScale", useUniform, pp.frgScale);
1286 MovePtr<ProgramWrapper> program = createShaderProgram(&vtxSrc, &frgSrc, false);
1287 GLuint progName = program->getProgramName();
1288
1289 log() << TestLog::Message << "// Created monolithic shader program " << progName << TestLog::EndMessage;
1290
1291 if (useUniform)
1292 {
1293 setUniform(*program, "vtxScale", pp.vtxScale, false);
1294 setUniform(*program, "frgScale", pp.frgScale, false);
1295 }
1296
1297 return program;
1298 }
1299
drawSurface(Surface & dst,uint32_t seed)1300 void SeparateShaderTest::drawSurface(Surface &dst, uint32_t seed)
1301 {
1302 const RenderContext &renderCtx = getRenderContext();
1303 Random rnd(seed > 0 ? seed : m_rnd.getUint32());
1304 Rectangle viewport = randomViewport(renderCtx, rnd, VIEWPORT_SIZE, VIEWPORT_SIZE);
1305 uint32_t vao = 0;
1306
1307 if (!glu::isContextTypeES(renderCtx.getType()))
1308 {
1309 glGenVertexArrays(1, &vao);
1310 glBindVertexArray(vao);
1311 }
1312
1313 glClearColor(0.125f, 0.25f, 0.5f, 1.f);
1314 setViewport(renderCtx, viewport);
1315 glClear(GL_COLOR_BUFFER_BIT);
1316 GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
1317 readRectangle(renderCtx, viewport, dst);
1318 log().writeMessage("// Drew a triangle");
1319
1320 if (vao)
1321 glDeleteVertexArrays(1, &vao);
1322 }
1323
testPipelineRendering(MovePtr<Pipeline> & pipeOut)1324 void SeparateShaderTest::testPipelineRendering(MovePtr<Pipeline> &pipeOut)
1325 {
1326 ProgramParams pp = genProgramParams(m_rnd);
1327 Pipeline &pipeline = *(pipeOut = createPipeline(pp));
1328 GLuint pipeName = pipeline.pipeline->getPipeline();
1329 UniquePtr<ProgramWrapper> refProgram(createReferenceProgram(pp));
1330 GLuint refProgName = refProgram->getProgramName();
1331 Surface refSurface;
1332 Surface pipelineSurface;
1333 GLuint drawSeed = m_rnd.getUint32();
1334
1335 glUseProgram(refProgName);
1336 log() << TestLog::Message << "// Use program " << refProgName << TestLog::EndMessage;
1337 drawSurface(refSurface, drawSeed);
1338 glUseProgram(0);
1339
1340 glBindProgramPipeline(pipeName);
1341 log() << TestLog::Message << "// Bind pipeline " << pipeName << TestLog::EndMessage;
1342 drawSurface(pipelineSurface, drawSeed);
1343 glBindProgramPipeline(0);
1344
1345 {
1346 const bool result = tcu::fuzzyCompare(m_testCtx.getLog(), "Program pipeline result",
1347 "Result of comparing a program pipeline with a monolithic program",
1348 refSurface, pipelineSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1349
1350 m_status.check(result, "Pipeline rendering differs from equivalent monolithic program");
1351 }
1352 }
1353
testCurrentProgPriority(MovePtr<Pipeline> & pipeOut)1354 void SeparateShaderTest::testCurrentProgPriority(MovePtr<Pipeline> &pipeOut)
1355 {
1356 ProgramParams pipePp = genProgramParams(m_rnd);
1357 ProgramParams programPp = genProgramParams(m_rnd);
1358 Pipeline &pipeline = *(pipeOut = createPipeline(pipePp));
1359 GLuint pipeName = pipeline.pipeline->getPipeline();
1360 UniquePtr<ProgramWrapper> program(createReferenceProgram(programPp));
1361 Surface pipelineSurface;
1362 Surface refSurface;
1363 Surface resultSurface;
1364 uint32_t drawSeed = m_rnd.getUint32();
1365
1366 LOG_CALL(glBindProgramPipeline(pipeName));
1367 drawSurface(pipelineSurface, drawSeed);
1368 LOG_CALL(glBindProgramPipeline(0));
1369
1370 LOG_CALL(glUseProgram(program->getProgramName()));
1371 drawSurface(refSurface, drawSeed);
1372 LOG_CALL(glUseProgram(0));
1373
1374 LOG_CALL(glUseProgram(program->getProgramName()));
1375 LOG_CALL(glBindProgramPipeline(pipeName));
1376 drawSurface(resultSurface, drawSeed);
1377 LOG_CALL(glBindProgramPipeline(0));
1378 LOG_CALL(glUseProgram(0));
1379
1380 bool result = tcu::pixelThresholdCompare(m_testCtx.getLog(), "Active program rendering result",
1381 "Active program rendering result", refSurface, resultSurface,
1382 tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1383
1384 m_status.check(result, "glBindProgramPipeline() affects glUseProgram()");
1385 if (!result)
1386 log() << TestLog::Image("Pipeline image", "Image produced by pipeline", pipelineSurface);
1387 }
1388
testActiveProgramUniform(MovePtr<Pipeline> & pipeOut)1389 void SeparateShaderTest::testActiveProgramUniform(MovePtr<Pipeline> &pipeOut)
1390 {
1391 ProgramParams refPp = genProgramParams(m_rnd);
1392 Surface refSurface;
1393 Surface resultSurface;
1394 uint32_t drawSeed = m_rnd.getUint32();
1395
1396 DE_UNREF(pipeOut);
1397 {
1398 UniquePtr<ProgramWrapper> refProg(createReferenceProgram(refPp));
1399 GLuint refProgName = refProg->getProgramName();
1400
1401 glUseProgram(refProgName);
1402 log() << TestLog::Message << "// Use reference program " << refProgName << TestLog::EndMessage;
1403 drawSurface(refSurface, drawSeed);
1404 glUseProgram(0);
1405 }
1406
1407 {
1408 ProgramParams changePp = genProgramParams(m_rnd);
1409 changePp.vtxSeed = refPp.vtxSeed;
1410 changePp.frgSeed = refPp.frgSeed;
1411 UniquePtr<ProgramWrapper> changeProg(createReferenceProgram(changePp));
1412 GLuint changeName = changeProg->getProgramName();
1413 ProgramPipeline pipeline(getRenderContext());
1414 GLint vtxLoc = glGetUniformLocation(changeName, "vtxScale");
1415 GLint frgLoc = glGetUniformLocation(changeName, "frgScale");
1416
1417 LOG_CALL(glBindProgramPipeline(pipeline.getPipeline()));
1418
1419 pipeline.activeShaderProgram(changeName);
1420 log() << TestLog::Message << "// Set active shader program to " << changeName << TestLog::EndMessage;
1421
1422 glUniform1f(vtxLoc, refPp.vtxScale);
1423 log() << TestLog::Message << "// Set uniform 'vtxScale' to " << refPp.vtxScale << " using glUniform1f"
1424 << TestLog::EndMessage;
1425 glUniform1f(frgLoc, refPp.frgScale);
1426 log() << TestLog::Message << "// Set uniform 'frgScale' to " << refPp.frgScale << " using glUniform1f"
1427 << TestLog::EndMessage;
1428
1429 pipeline.activeShaderProgram(0);
1430 LOG_CALL(glBindProgramPipeline(0));
1431
1432 LOG_CALL(glUseProgram(changeName));
1433 drawSurface(resultSurface, drawSeed);
1434 LOG_CALL(glUseProgram(0));
1435 }
1436
1437 bool result =
1438 tcu::fuzzyCompare(m_testCtx.getLog(), "Active program uniform result", "Active program uniform result",
1439 refSurface, resultSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1440
1441 m_status.check(result, "glUniform() did not correctly modify "
1442 "the active program of the bound pipeline");
1443 }
1444
testPipelineQueryPrograms(MovePtr<Pipeline> & pipeOut)1445 void SeparateShaderTest::testPipelineQueryPrograms(MovePtr<Pipeline> &pipeOut)
1446 {
1447 ProgramParams pipePp = genProgramParams(m_rnd);
1448 Pipeline &pipeline = *(pipeOut = createPipeline(pipePp));
1449 GLuint pipeName = pipeline.pipeline->getPipeline();
1450 GLint queryVtx = 0;
1451 GLint queryFrg = 0;
1452
1453 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_VERTEX_SHADER, &queryVtx)));
1454 m_status.check(GLuint(queryVtx) == pipeline.getVertexProgram().getProgramName(),
1455 "Program pipeline query reported wrong vertex shader program");
1456
1457 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_FRAGMENT_SHADER, &queryFrg)));
1458 m_status.check(GLuint(queryFrg) == pipeline.getFragmentProgram().getProgramName(),
1459 "Program pipeline query reported wrong fragment shader program");
1460 }
1461
testPipelineQueryActive(MovePtr<Pipeline> & pipeOut)1462 void SeparateShaderTest::testPipelineQueryActive(MovePtr<Pipeline> &pipeOut)
1463 {
1464 ProgramParams pipePp = genProgramParams(m_rnd);
1465 Pipeline &pipeline = *(pipeOut = createPipeline(pipePp));
1466 GLuint pipeName = pipeline.pipeline->getPipeline();
1467 GLuint newActive = pipeline.getVertexProgram().getProgramName();
1468 GLint queryActive = 0;
1469
1470 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1471 m_status.check(queryActive == 0, "Program pipeline query reported non-zero initial active program");
1472
1473 pipeline.pipeline->activeShaderProgram(newActive);
1474 log() << TestLog::Message << "Set pipeline " << pipeName << "'s active shader program to " << newActive
1475 << TestLog::EndMessage;
1476
1477 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1478 m_status.check(GLuint(queryActive) == newActive, "Program pipeline query reported incorrect active program");
1479
1480 pipeline.pipeline->activeShaderProgram(0);
1481 }
1482
iterate(void)1483 TestCase::IterateResult SeparateShaderTest::iterate(void)
1484 {
1485 MovePtr<Pipeline> pipeline;
1486
1487 DE_ASSERT(m_iterations > 0);
1488
1489 if (m_currentIteration == 0)
1490 logParams(log(), m_params);
1491
1492 ++m_currentIteration;
1493
1494 try
1495 {
1496 (this->*m_testFunc)(pipeline);
1497 log().writeMessage("");
1498 }
1499 catch (const tcu::Exception &)
1500 {
1501 if (pipeline)
1502 logPipeline(log(), *pipeline);
1503 throw;
1504 }
1505
1506 if (m_status.getResult() != QP_TEST_RESULT_PASS)
1507 {
1508 if (pipeline)
1509 logPipeline(log(), *pipeline);
1510 }
1511 else if (m_currentIteration < m_iterations)
1512 return CONTINUE;
1513
1514 m_status.setTestContextResult(m_testCtx);
1515 return STOP;
1516 }
1517
1518 // Group construction utilities
1519
1520 enum ParamFlags
1521 {
1522 PARAMFLAGS_SWITCH_FRAGMENT = 1 << 0,
1523 PARAMFLAGS_SWITCH_VERTEX = 1 << 1,
1524 PARAMFLAGS_INIT_SINGLE = 1 << 2,
1525 PARAMFLAGS_LAST = 1 << 3,
1526 PARAMFLAGS_MASK = PARAMFLAGS_LAST - 1
1527 };
1528
areCaseParamFlagsValid(ParamFlags flags)1529 bool areCaseParamFlagsValid(ParamFlags flags)
1530 {
1531 const ParamFlags switchAll = ParamFlags(PARAMFLAGS_SWITCH_VERTEX | PARAMFLAGS_SWITCH_FRAGMENT);
1532
1533 if ((flags & PARAMFLAGS_INIT_SINGLE) != 0)
1534 return (flags & switchAll) == 0 || (flags & switchAll) == switchAll;
1535 else
1536 return true;
1537 }
1538
addRenderTest(TestCaseGroup & group,const string & namePrefix,const string & descPrefix,int numIterations,ParamFlags flags,TestParams params)1539 bool addRenderTest(TestCaseGroup &group, const string &namePrefix, const string &descPrefix, int numIterations,
1540 ParamFlags flags, TestParams params)
1541 {
1542 ostringstream name;
1543 ostringstream desc;
1544
1545 DE_ASSERT(areCaseParamFlagsValid(flags));
1546
1547 name << namePrefix;
1548 desc << descPrefix;
1549
1550 params.initSingle = (flags & PARAMFLAGS_INIT_SINGLE) != 0;
1551 params.switchVtx = (flags & PARAMFLAGS_SWITCH_VERTEX) != 0;
1552 params.switchFrg = (flags & PARAMFLAGS_SWITCH_FRAGMENT) != 0;
1553
1554 name << (flags & PARAMFLAGS_INIT_SINGLE ? "single_program" : "separate_programs");
1555 desc << (flags & PARAMFLAGS_INIT_SINGLE ? "Single program with two shaders" : "Separate programs for each shader");
1556
1557 switch (flags & (PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX))
1558 {
1559 case 0:
1560 break;
1561 case PARAMFLAGS_SWITCH_FRAGMENT:
1562 name << "_add_fragment";
1563 desc << ", then add a fragment program";
1564 break;
1565 case PARAMFLAGS_SWITCH_VERTEX:
1566 name << "_add_vertex";
1567 desc << ", then add a vertex program";
1568 break;
1569 case PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX:
1570 name << "_add_both";
1571 desc << ", then add both vertex and shader programs";
1572 break;
1573 }
1574
1575 if (!paramsValid(params))
1576 return false;
1577
1578 group.addChild(new SeparateShaderTest(group.getContext(), name.str(), desc.str(), numIterations, params,
1579 &SeparateShaderTest::testPipelineRendering));
1580
1581 return true;
1582 }
1583
describeInterpolation(const string & stage,VaryingInterpolation qual,ostringstream & name,ostringstream & desc)1584 void describeInterpolation(const string &stage, VaryingInterpolation qual, ostringstream &name, ostringstream &desc)
1585 {
1586 DE_ASSERT(qual < VARYINGINTERPOLATION_RANDOM);
1587
1588 if (qual == VARYINGINTERPOLATION_DEFAULT)
1589 {
1590 desc << ", unqualified in " << stage << " shader";
1591 return;
1592 }
1593 else
1594 {
1595 const string qualName = glu::getInterpolationName(getGluInterpolation(qual));
1596
1597 name << "_" << stage << "_" << qualName;
1598 desc << ", qualified '" << qualName << "' in " << stage << " shader";
1599 }
1600 }
1601
1602 } // namespace
1603
createCommonSeparateShaderTests(Context & ctx)1604 TestCaseGroup *createCommonSeparateShaderTests(Context &ctx)
1605 {
1606 TestParams defaultParams;
1607 int numIterations = 4;
1608 TestCaseGroup *group = new TestCaseGroup(ctx, "separate_shader", "Separate shader tests");
1609
1610 defaultParams.useUniform = false;
1611 defaultParams.initSingle = false;
1612 defaultParams.switchVtx = false;
1613 defaultParams.switchFrg = false;
1614 defaultParams.useCreateHelper = false;
1615 defaultParams.useProgramUniform = false;
1616 defaultParams.useSameName = false;
1617 defaultParams.varyings.count = 0;
1618 defaultParams.varyings.type = glu::TYPE_INVALID;
1619 defaultParams.varyings.binding = BINDING_NAME;
1620 defaultParams.varyings.vtxInterp = VARYINGINTERPOLATION_LAST;
1621 defaultParams.varyings.frgInterp = VARYINGINTERPOLATION_LAST;
1622
1623 TestCaseGroup *stagesGroup = new TestCaseGroup(ctx, "pipeline", "Pipeline configuration tests");
1624 group->addChild(stagesGroup);
1625
1626 for (uint32_t flags = 0; flags < PARAMFLAGS_LAST << 2; ++flags)
1627 {
1628 TestParams params = defaultParams;
1629 ostringstream name;
1630 ostringstream desc;
1631
1632 if (!areCaseParamFlagsValid(ParamFlags(flags & PARAMFLAGS_MASK)))
1633 continue;
1634
1635 if (flags & (PARAMFLAGS_LAST << 1))
1636 {
1637 params.useSameName = true;
1638 name << "same_";
1639 desc << "Identically named ";
1640 }
1641 else
1642 {
1643 name << "different_";
1644 desc << "Differently named ";
1645 }
1646
1647 if (flags & PARAMFLAGS_LAST)
1648 {
1649 params.useUniform = true;
1650 name << "uniform_";
1651 desc << "uniforms, ";
1652 }
1653 else
1654 {
1655 name << "constant_";
1656 desc << "constants, ";
1657 }
1658
1659 addRenderTest(*stagesGroup, name.str(), desc.str(), numIterations, ParamFlags(flags & PARAMFLAGS_MASK), params);
1660 }
1661
1662 TestCaseGroup *programUniformGroup = new TestCaseGroup(ctx, "program_uniform", "ProgramUniform tests");
1663 group->addChild(programUniformGroup);
1664
1665 for (uint32_t flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1666 {
1667 TestParams params = defaultParams;
1668
1669 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1670 continue;
1671
1672 params.useUniform = true;
1673 params.useProgramUniform = true;
1674
1675 addRenderTest(*programUniformGroup, "", "", numIterations, ParamFlags(flags), params);
1676 }
1677
1678 TestCaseGroup *createShaderProgramGroup =
1679 new TestCaseGroup(ctx, "create_shader_program", "CreateShaderProgram tests");
1680 group->addChild(createShaderProgramGroup);
1681
1682 for (uint32_t flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1683 {
1684 TestParams params = defaultParams;
1685
1686 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1687 continue;
1688
1689 params.useCreateHelper = true;
1690
1691 addRenderTest(*createShaderProgramGroup, "", "", numIterations, ParamFlags(flags), params);
1692 }
1693
1694 TestCaseGroup *interfaceGroup = new TestCaseGroup(ctx, "interface", "Shader interface compatibility tests");
1695 group->addChild(interfaceGroup);
1696
1697 enum
1698 {
1699 NUM_INTERPOLATIONS =
1700 VARYINGINTERPOLATION_RANDOM, // VARYINGINTERPOLATION_RANDOM is one after last fully specified interpolation
1701 INTERFACEFLAGS_LAST =
1702 static_cast<int>(BINDING_LAST) * static_cast<int>(NUM_INTERPOLATIONS) * static_cast<int>(NUM_INTERPOLATIONS)
1703 };
1704
1705 for (uint32_t flags = 0; flags < INTERFACEFLAGS_LAST; ++flags)
1706 {
1707 uint32_t tmpFlags = flags;
1708 VaryingInterpolation frgInterp = VaryingInterpolation(tmpFlags % NUM_INTERPOLATIONS);
1709 VaryingInterpolation vtxInterp = VaryingInterpolation((tmpFlags /= NUM_INTERPOLATIONS) % NUM_INTERPOLATIONS);
1710 BindingKind binding = BindingKind((tmpFlags /= NUM_INTERPOLATIONS) % BINDING_LAST);
1711 TestParams params = defaultParams;
1712 ostringstream name;
1713 ostringstream desc;
1714
1715 params.varyings.count = 1;
1716 params.varyings.type = glu::TYPE_FLOAT;
1717 params.varyings.binding = binding;
1718 params.varyings.vtxInterp = vtxInterp;
1719 params.varyings.frgInterp = frgInterp;
1720
1721 switch (binding)
1722 {
1723 case BINDING_LOCATION:
1724 name << "same_location";
1725 desc << "Varyings have same location, ";
1726 break;
1727 case BINDING_NAME:
1728 name << "same_name";
1729 desc << "Varyings have same name, ";
1730 break;
1731 default:
1732 DE_FATAL("Impossible");
1733 }
1734
1735 describeInterpolation("vertex", vtxInterp, name, desc);
1736 describeInterpolation("fragment", frgInterp, name, desc);
1737
1738 if (!paramsValid(params))
1739 continue;
1740
1741 interfaceGroup->addChild(new SeparateShaderTest(ctx, name.str(), desc.str(), numIterations, params,
1742 &SeparateShaderTest::testPipelineRendering));
1743 }
1744
1745 uint32_t baseSeed = ctx.getTestContext().getCommandLine().getBaseSeed();
1746 Random rnd(deStringHash("separate_shader.random") + baseSeed);
1747 set<string> seen;
1748 TestCaseGroup *randomGroup = new TestCaseGroup(ctx, "random", "Random pipeline configuration tests");
1749 group->addChild(randomGroup);
1750
1751 for (uint32_t i = 0; i < 128; ++i)
1752 {
1753 TestParams params;
1754 string code;
1755 uint32_t genIterations = 4096;
1756
1757 do
1758 {
1759 params = genParams(rnd.getUint32());
1760 code = paramsCode(params);
1761 } while (de::contains(seen, code) && --genIterations > 0);
1762
1763 seen.insert(code);
1764
1765 string name = de::toString(i); // Would be code but baseSeed can change
1766
1767 randomGroup->addChild(
1768 new SeparateShaderTest(ctx, name, name, numIterations, params, &SeparateShaderTest::testPipelineRendering));
1769 }
1770
1771 TestCaseGroup *apiGroup = new TestCaseGroup(ctx, "api", "Program pipeline API tests");
1772 group->addChild(apiGroup);
1773
1774 {
1775 // More or less random parameters. These shouldn't have much effect, so just
1776 // do a single sample.
1777 TestParams params = defaultParams;
1778 params.useUniform = true;
1779 apiGroup->addChild(new SeparateShaderTest(ctx, "current_program_priority",
1780 "Test priority between current program and pipeline binding", 1,
1781 params, &SeparateShaderTest::testCurrentProgPriority));
1782 apiGroup->addChild(new SeparateShaderTest(ctx, "active_program_uniform",
1783 "Test that glUniform() affects a pipeline's active program", 1,
1784 params, &SeparateShaderTest::testActiveProgramUniform));
1785
1786 apiGroup->addChild(new SeparateShaderTest(ctx, "pipeline_programs",
1787 "Test queries for programs in program pipeline stages", 1, params,
1788 &SeparateShaderTest::testPipelineQueryPrograms));
1789
1790 apiGroup->addChild(new SeparateShaderTest(ctx, "pipeline_active",
1791 "Test query for active programs in a program pipeline", 1, params,
1792 &SeparateShaderTest::testPipelineQueryActive));
1793 }
1794
1795 return group;
1796 }
1797
createGLESSeparateShaderTests(Context & ctx)1798 TestCaseGroup *createGLESSeparateShaderTests(Context &ctx)
1799 {
1800 TestCaseGroup *group = createCommonSeparateShaderTests(ctx);
1801
1802 TestCaseGroup *interfaceMismatchGroup =
1803 new TestCaseGroup(ctx, "validation", "Negative program pipeline interface matching");
1804 group->addChild(interfaceMismatchGroup);
1805
1806 {
1807 TestCaseGroup *es31Group = new TestCaseGroup(ctx, "es31", "GLSL ES 3.1 pipeline interface matching");
1808 gls::ShaderLibrary shaderLibrary(ctx.getTestContext(), ctx.getRenderContext(), ctx.getContextInfo());
1809 const std::vector<tcu::TestNode *> children =
1810 shaderLibrary.loadShaderFile("shaders/es31/separate_shader_validation.test");
1811
1812 for (int i = 0; i < (int)children.size(); i++)
1813 es31Group->addChild(children[i]);
1814
1815 interfaceMismatchGroup->addChild(es31Group);
1816 }
1817
1818 {
1819 TestCaseGroup *es32Group = new TestCaseGroup(ctx, "es32", "GLSL ES 3.2 pipeline interface matching");
1820 gls::ShaderLibrary shaderLibrary(ctx.getTestContext(), ctx.getRenderContext(), ctx.getContextInfo());
1821 const std::vector<tcu::TestNode *> children =
1822 shaderLibrary.loadShaderFile("shaders/es32/separate_shader_validation.test");
1823
1824 for (int i = 0; i < (int)children.size(); i++)
1825 es32Group->addChild(children[i]);
1826
1827 interfaceMismatchGroup->addChild(es32Group);
1828 }
1829
1830 return group;
1831 }
1832 } // namespace Functional
1833 } // namespace gles31
1834 } // namespace deqp
1835