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