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