1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Tests for separate shader objects
22 *//*--------------------------------------------------------------------*/
24 #include "es31fSeparateShaderTests.hpp"
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"
67 using std::ostringstream;
73 using tcu::MessageBuilder;
74 using tcu::RenderTarget;
75 using tcu::StringTemplate;
78 using tcu::ResultCollector;
79 using glu::CallLogWrapper;
81 using glu::VariableDeclaration;
82 using glu::Interpolation;
85 using glu::ProgramPipeline;
86 using glu::ProgramSources;
87 using glu::RenderContext;
88 using glu::ShaderProgram;
89 using glu::ShaderType;
92 using glu::VertexSource;
93 using glu::FragmentSource;
94 using glu::ProgramSeparable;
98 #define LOG_CALL(CALL) do \
100 enableLogging(true); \
102 enableLogging(false); \
103 } while (deGetFalse())
110 DataType randomType (Random& rnd)
114 if (rnd.getInt(0, 7) == 0)
116 const int numCols = rnd.getInt(2, 4), numRows = rnd.getInt(2, 4);
118 return getDataTypeMatrix(numCols, numRows);
122 static const DataType s_types[] = { TYPE_FLOAT, TYPE_INT, TYPE_UINT };
123 static const float s_weights[] = { 3.0, 1.0, 1.0 };
124 const int size = rnd.getInt(1, 4);
125 const DataType scalarType = rnd.chooseWeighted<DataType>(
126 DE_ARRAY_BEGIN(s_types), DE_ARRAY_END(s_types), DE_ARRAY_BEGIN(s_weights));
127 return getDataTypeVector(scalarType, size);
130 DE_ASSERT(!"Impossible");
134 Interpolation randomInterpolation (Random& rnd)
136 return Interpolation(rnd.getInt(0, glu::INTERPOLATION_LAST - 1));
146 BindingKind randomBinding (Random& rnd)
148 return rnd.getBool() ? BINDING_LOCATION : BINDING_NAME;
151 void printInputColor (ostringstream& oss, const VariableDeclaration& input)
155 const DataType basicType = input.varType.getBasicType();
156 string exp = input.name;
158 switch (getDataTypeScalarType(basicType))
166 DataType floatType = getDataTypeFloatScalars(basicType);
167 exp = string() + "(" + getDataTypeName(floatType) + "(" + exp + ") / 255.0" + ")";
172 DE_ASSERT(!"Impossible");
175 if (isDataTypeScalarOrVector(basicType))
177 switch (getDataTypeScalarSize(basicType))
180 oss << "hsv(vec3(" << exp << ", 1.0, 1.0))";
183 oss << "hsv(vec3(" << exp << ", 1.0))";
186 oss << "vec4(" << exp << ", 1.0)";
192 DE_ASSERT(!"Impossible");
195 else if (isDataTypeMatrix(basicType))
197 int rows = getDataTypeMatrixNumRows(basicType);
198 int columns = getDataTypeMatrixNumColumns(basicType);
201 oss << "hsv(vec3(determinant(" << exp << ")))";
204 if (rows != 3 && columns >= 3)
206 exp = "transpose(" + exp + ")";
207 std::swap(rows, columns);
212 oss << "hsv(" << exp << ")";
216 DE_ASSERT(!"Impossible");
219 // Representation for the varyings between vertex and fragment shaders
225 , type (glu::TYPE_LAST)
226 , binding (BINDING_LAST)
227 , vtxInterp (glu::INTERPOLATION_LAST)
228 , frgInterp (glu::INTERPOLATION_LAST) {}
233 Interpolation vtxInterp;
234 Interpolation frgInterp;
237 struct VaryingInterface
239 vector<VariableDeclaration> vtxOutputs;
240 vector<VariableDeclaration> frgInputs;
243 // Generate corresponding input and output variable declarations that may vary
244 // in compatible ways.
246 Interpolation chooseInterpolation (Interpolation param, DataType type, Random& rnd)
248 if (glu::getDataTypeScalarType(type) != glu::TYPE_FLOAT)
249 return glu::INTERPOLATION_FLAT;
251 if (param == glu::INTERPOLATION_LAST)
252 return randomInterpolation(rnd);
257 VaryingInterface genVaryingInterface (const VaryingParams& params,
262 VaryingInterface ret;
265 for (int varNdx = 0; varNdx < params.count; ++varNdx)
267 const BindingKind binding = ((params.binding == BINDING_LAST)
268 ? randomBinding(rnd) : params.binding);
269 const DataType type = ((params.type == TYPE_LAST)
270 ? randomType(rnd) : params.type);
271 const Interpolation vtxInterp = chooseInterpolation(params.vtxInterp, type, rnd);
272 const Interpolation frgInterp = chooseInterpolation(params.frgInterp, type, rnd);
273 const int loc = ((binding == BINDING_LOCATION) ? offset : -1);
274 const string ndxStr = de::toString(varNdx);
275 const string vtxName = ((binding == BINDING_NAME)
276 ? "var" + ndxStr : "vtxVar" + ndxStr);
277 const string frgName = ((binding == BINDING_NAME)
278 ? "var" + ndxStr : "frgVar" + ndxStr);
279 const VarType varType (type, PRECISION_HIGHP);
281 offset += getDataTypeNumLocations(type);
283 // Over 16 locations aren't necessarily supported, so halt here.
287 ret.vtxOutputs.push_back(
288 VariableDeclaration(varType, vtxName, STORAGE_OUT, vtxInterp, loc));
289 ret.frgInputs.push_back(
290 VariableDeclaration(varType, frgName, STORAGE_IN, frgInterp, loc));
296 // Create vertex output variable declarations that are maximally compatible
297 // with the fragment input variables.
299 vector<VariableDeclaration> varyingCompatVtxOutputs (const VaryingInterface& varyings)
301 vector<VariableDeclaration> outputs = varyings.vtxOutputs;
303 for (size_t i = 0; i < outputs.size(); ++i)
305 outputs[i].interpolation = varyings.frgInputs[i].interpolation;
306 outputs[i].name = varyings.frgInputs[i].name;
312 // Shader source generation
314 void printFloat (ostringstream& oss, double d)
316 oss.setf(oss.fixed | oss.internal);
322 void printFloatDeclaration (ostringstream& oss,
323 const string& varName,
329 const VarType varType (TYPE_FLOAT, PRECISION_HIGHP);
332 oss << VariableDeclaration(varType, varName, STORAGE_UNIFORM) << ";\n";
334 oss << VariableDeclaration(varType, varName, STORAGE_CONST)
335 << " = " << de::floatToString(value, 6) << ";\n";
338 void printRandomInitializer (ostringstream& oss, DataType type, Random& rnd)
341 const int size = getDataTypeScalarSize(type);
344 oss << getDataTypeName(type) << "(";
346 for (int i = 0; i < size; ++i)
348 oss << (i == 0 ? "" : ", ");
349 switch (getDataTypeScalarType(type))
352 printFloat(oss, rnd.getInt(0, 16) / 16.0);
357 oss << rnd.getInt(0, 255);
361 oss << (rnd.getBool() ? "true" : "false");
365 DE_ASSERT(!"Impossible");
373 string genVtxShaderSrc (deUint32 seed,
374 const vector<VariableDeclaration>& outputs,
375 const string& varName,
381 enum { NUM_COMPONENTS = 2 };
382 static const int s_quadrants[][NUM_COMPONENTS] = { {1, 1}, {-1, 1}, {1, -1} };
384 oss << "#version 310 es\n";
386 oss << "const vec2 triangle[3] = vec2[3](\n";
388 for (int vertexNdx = 0; vertexNdx < DE_LENGTH_OF_ARRAY(s_quadrants); ++vertexNdx)
392 for (int componentNdx = 0; componentNdx < NUM_COMPONENTS; ++componentNdx)
394 printFloat(oss, s_quadrants[vertexNdx][componentNdx] * rnd.getInt(4,16) / 16.0);
395 oss << (componentNdx < 1 ? ", " : "");
398 oss << ")" << (vertexNdx < 2 ? "," : "") << "\n";
403 for (vector<VariableDeclaration>::const_iterator it = outputs.begin();
404 it != outputs.end(); ++it)
406 const DataType type = it->varType.getBasicType();
407 const string typeName = glu::getDataTypeName(type);
409 oss << "const " << typeName << " " << it->name << "Inits[3] = "
410 << typeName << "[3](\n";
411 for (int i = 0; i < 3; ++i)
413 oss << (i == 0 ? "\t" : ",\n\t");
414 printRandomInitializer(oss, type, rnd);
420 printFloatDeclaration(oss, varName, uniform, value);
422 oss << "void main (void)\n"
424 << "\tgl_Position = vec4(" << varName << " * triangle[gl_VertexID], 0.0, 1.0);\n";
426 for (vector<VariableDeclaration>::const_iterator it = outputs.begin();
427 it != outputs.end(); ++it)
428 oss << "\t" << it->name << " = " << it->name << "Inits[gl_VertexID];\n";
435 string genFrgShaderSrc (deUint32 seed,
436 const vector<VariableDeclaration>& inputs,
437 const string& varName,
446 oss << "#version 310 es\n";
448 oss << "precision highp float;\n";;
450 oss << "out vec4 fragColor;\n";;
452 printFloatDeclaration(oss, varName, uniform, value);
454 for (vector<VariableDeclaration>::const_iterator it = inputs.begin();
455 it != inputs.end(); ++it)
458 // glsl % isn't defined for negative numbers
459 oss << "int imod (int n, int d)" << "\n"
461 << "\t" << "return (n < 0 ? d - 1 - (-1 - n) % d : n % d);" << "\n"
464 oss << "vec4 hsv (vec3 hsv)"
466 << "\tfloat h = hsv.x * 3.0;\n"
467 << "\tfloat r = max(0.0, 1.0 - h) + max(0.0, h - 2.0);\n"
468 << "\tfloat g = max(0.0, 1.0 - abs(h - 1.0));\n"
469 << "\tfloat b = max(0.0, 1.0 - abs(h - 2.0));\n"
470 << "\tvec3 hs = mix(vec3(1.0), vec3(r, g, b), hsv.y);\n"
471 << "\treturn vec4(hsv.z * hs, 1.0);\n"
474 oss << "void main (void)\n"
477 oss << "\t" << "fragColor = vec4(vec3(" << varName << "), 1.0);" << "\n";
479 if (inputs.size() > 0)
481 oss << "\t" << "switch (imod(int(0.5 * (gl_FragCoord.x - gl_FragCoord.y)), "
482 << inputs.size() << "))" << "\n"
483 << "\t" << "{" << "\n";
485 for (size_t i = 0; i < inputs.size(); ++i)
487 oss << "\t\t" << "case " << i << ":" << "\n"
488 << "\t\t\t" << "fragColor *= ";
490 printInputColor(oss, inputs[i]);
493 << "\t\t\t" << "break;" << "\n";
496 oss << "\t\t" << "case " << inputs.size() << ":\n"
497 << "\t\t\t" << "fragColor = vec4(1.0, 0.0, 1.0, 1.0);" << "\n";
498 oss << "\t\t\t" << "break;" << "\n";
500 oss << "\t\t" << "case -1:\n"
501 << "\t\t\t" << "fragColor = vec4(1.0, 1.0, 0.0, 1.0);" << "\n";
502 oss << "\t\t\t" << "break;" << "\n";
504 oss << "\t\t" << "default:" << "\n"
505 << "\t\t\t" << "fragColor = vec4(1.0, 1.0, 0.0, 1.0);" << "\n";
507 oss << "\t" << "}\n";
521 virtual ~ProgramWrapper (void) {}
523 virtual GLuint getProgramName (void) = 0;
524 virtual void writeToLog (TestLog& log) = 0;
527 class ShaderProgramWrapper : public ProgramWrapper
530 ShaderProgramWrapper (const RenderContext& renderCtx,
531 const ProgramSources& sources)
532 : m_shaderProgram (renderCtx, sources) {}
533 ~ShaderProgramWrapper (void) {}
535 GLuint getProgramName (void) { return m_shaderProgram.getProgram(); }
536 ShaderProgram& getShaderProgram (void) { return m_shaderProgram; }
537 void writeToLog (TestLog& log) { log << m_shaderProgram; }
540 ShaderProgram m_shaderProgram;
543 class RawProgramWrapper : public ProgramWrapper
546 RawProgramWrapper (const RenderContext& renderCtx,
548 ShaderType shaderType,
549 const string& source)
550 : m_program (renderCtx, programName)
551 , m_shaderType (shaderType)
552 , m_source (source) {}
553 ~RawProgramWrapper (void) {}
555 GLuint getProgramName (void) { return m_program.getProgram(); }
556 Program& getProgram (void) { return m_program; }
557 void writeToLog (TestLog& log);
561 ShaderType m_shaderType;
562 const string m_source;
565 void RawProgramWrapper::writeToLog (TestLog& log)
567 const string info = m_program.getInfoLog();
568 qpShaderType qpType = glu::getLogShaderType(m_shaderType);
570 log << TestLog::ShaderProgram(true, info)
571 << TestLog::Shader(qpType, m_source,
572 true, "[Shader created by glCreateShaderProgramv()]")
573 << TestLog::EndShaderProgram;
580 ProgramParams (deUint32 vtxSeed_, GLfloat vtxScale_, deUint32 frgSeed_, GLfloat frgScale_)
582 , vtxScale (vtxScale_)
584 , frgScale (frgScale_) {}
591 ProgramParams genProgramParams (Random& rnd)
593 const deUint32 vtxSeed = rnd.getUint32();
594 const GLfloat vtxScale = rnd.getInt(8, 16) / 16.0f;
595 const deUint32 frgSeed = rnd.getUint32();
596 const GLfloat frgScale = rnd.getInt(0, 16) / 16.0f;
598 return ProgramParams(vtxSeed, vtxScale, frgSeed, frgScale);
610 bool useCreateHelper;
611 bool useProgramUniform;
612 VaryingParams varyings;
615 deUint32 paramsSeed (const TestParams& params)
617 deUint32 paramCode = (params.initSingle << 0 |
618 params.switchVtx << 1 |
619 params.switchFrg << 2 |
620 params.useUniform << 3 |
621 params.useSameName << 4 |
622 params.useCreateHelper << 5 |
623 params.useProgramUniform << 6);
625 paramCode = deUint32Hash(paramCode) + params.varyings.count;
626 paramCode = deUint32Hash(paramCode) + params.varyings.type;
627 paramCode = deUint32Hash(paramCode) + params.varyings.binding;
628 paramCode = deUint32Hash(paramCode) + params.varyings.vtxInterp;
629 paramCode = deUint32Hash(paramCode) + params.varyings.frgInterp;
631 return deUint32Hash(paramCode);
634 string paramsCode (const TestParams& params)
640 oss << (params.initSingle ? "1" : "2")
641 << (params.switchVtx ? "v" : "")
642 << (params.switchFrg ? "f" : "")
643 << (params.useProgramUniform ? "p" : "")
644 << (params.useUniform ? "u" : "")
645 << (params.useSameName ? "s" : "")
646 << (params.useCreateHelper ? "c" : "")
647 << de::toString(params.varyings.count)
648 << (params.varyings.binding == BINDING_NAME ? "n" :
649 params.varyings.binding == BINDING_LOCATION ? "l" :
650 params.varyings.binding == BINDING_LAST ? "r" :
652 << (params.varyings.vtxInterp == INTERPOLATION_SMOOTH ? "m" :
653 params.varyings.vtxInterp == INTERPOLATION_CENTROID ? "e" :
654 params.varyings.vtxInterp == INTERPOLATION_FLAT ? "a" :
655 params.varyings.vtxInterp == INTERPOLATION_LAST ? "r" :
657 << (params.varyings.frgInterp == INTERPOLATION_SMOOTH ? "m" :
658 params.varyings.frgInterp == INTERPOLATION_CENTROID ? "e" :
659 params.varyings.frgInterp == INTERPOLATION_FLAT ? "a" :
660 params.varyings.frgInterp == INTERPOLATION_LAST ? "r" :
665 bool paramsValid (const TestParams& params)
669 // Final pipeline has a single program?
670 if (params.initSingle)
672 // Cannot have conflicting names for uniforms or constants
673 if (params.useSameName)
676 // CreateShaderProgram would never get called
677 if (!params.switchVtx && !params.switchFrg && params.useCreateHelper)
680 // Must switch either all or nothing
681 if (params.switchVtx != params.switchFrg)
685 // ProgramUniform would never get called
686 if (params.useProgramUniform && !params.useUniform)
689 // Interpolation is meaningless if we don't use an in/out variable.
690 if (params.varyings.count == 0 &&
691 !(params.varyings.vtxInterp == INTERPOLATION_LAST &&
692 params.varyings.frgInterp == INTERPOLATION_LAST))
698 void logParams (TestLog& log, const TestParams& params)
700 // We don't log operational details here since those are shown
701 // in the log messages during execution.
702 MessageBuilder msg = log.message();
704 msg << "Pipeline configuration:\n";
706 msg << "Vertex and fragment shaders have "
707 << (params.useUniform ? "uniform" : "constant") << "s with "
708 << (params.useSameName ? "the same name" : "different names") << ".\n";
710 if (params.varyings.count == 0)
711 msg << "There are no varyings.\n";
714 if (params.varyings.count == 1)
715 msg << "There is one varying.\n";
717 msg << "There are " << params.varyings.count << " varyings.\n";
719 if (params.varyings.type == glu::TYPE_LAST)
720 msg << "Varyings are of random types.\n";
722 msg << "Varyings are of type '"
723 << glu::getDataTypeName(params.varyings.type) << "'.\n";
725 msg << "Varying outputs and inputs correspond ";
726 switch (params.varyings.binding)
731 case BINDING_LOCATION:
732 msg << "by location.\n";
735 msg << "randomly either by name or by location.\n";
738 DE_ASSERT(!"Impossible");
741 msg << "In the vertex shader the varyings are qualified ";
742 if (params.varyings.vtxInterp == glu::INTERPOLATION_LAST)
743 msg << "with a random interpolation qualifier.\n";
745 msg << "'" << glu::getInterpolationName(params.varyings.vtxInterp) << "'.\n";
747 msg << "In the fragment shader the varyings are qualified ";
748 if (params.varyings.frgInterp == glu::INTERPOLATION_LAST)
749 msg << "with a random interpolation qualifier.\n";
751 msg << "'" << glu::getInterpolationName(params.varyings.frgInterp) << "'.\n";
754 msg << TestLog::EndMessage;
756 log.writeMessage("");
759 TestParams genParams (deUint32 seed)
767 params.initSingle = rnd.getBool();
768 params.switchVtx = rnd.getBool();
769 params.switchFrg = rnd.getBool();
770 params.useUniform = rnd.getBool();
771 params.useProgramUniform = params.useUniform && rnd.getBool();
772 params.useCreateHelper = rnd.getBool();
773 params.useSameName = rnd.getBool();
775 int i = rnd.getInt(-1, 3);
776 params.varyings.count = (i == -1 ? 0 : 1 << i);
778 if (params.varyings.count > 0)
780 params.varyings.type = glu::TYPE_LAST;
781 params.varyings.binding = BINDING_LAST;
782 params.varyings.vtxInterp = glu::INTERPOLATION_LAST;
783 params.varyings.frgInterp = glu::INTERPOLATION_LAST;
787 params.varyings.type = glu::TYPE_INVALID;
788 params.varyings.binding = BINDING_LAST;
789 params.varyings.vtxInterp = glu::INTERPOLATION_LAST;
790 params.varyings.frgInterp = glu::INTERPOLATION_LAST;
794 } while (!paramsValid(params) && tryNdx < 16);
796 DE_ASSERT(paramsValid(params));
801 // Program pipeline wrapper that retains references to component programs.
805 Pipeline (MovePtr<ProgramPipeline> pipeline_,
806 MovePtr<ProgramWrapper> fullProg_,
807 MovePtr<ProgramWrapper> vtxProg_,
808 MovePtr<ProgramWrapper> frgProg_)
809 : pipeline (pipeline_)
810 , fullProg (fullProg_)
812 , frgProg (frgProg_) {}
814 ProgramWrapper& getVertexProgram (void) const
816 return vtxProg ? *vtxProg : *fullProg;
819 ProgramWrapper& getFragmentProgram (void) const
821 return frgProg ? *frgProg : *fullProg;
824 UniquePtr<ProgramPipeline> pipeline;
825 UniquePtr<ProgramWrapper> fullProg;
826 UniquePtr<ProgramWrapper> vtxProg;
827 UniquePtr<ProgramWrapper> frgProg;
830 void logPipeline(TestLog& log, const Pipeline& pipeline)
832 ProgramWrapper& vtxProg = pipeline.getVertexProgram();
833 ProgramWrapper& frgProg = pipeline.getFragmentProgram();
835 log.writeMessage("// Failed program pipeline:");
836 if (&vtxProg == &frgProg)
838 log.writeMessage("// Common program for both vertex and fragment stages:");
839 vtxProg.writeToLog(log);
843 log.writeMessage("// Vertex stage program:");
844 vtxProg.writeToLog(log);
845 log.writeMessage("// Fragment stage program:");
846 frgProg.writeToLog(log);
854 Rectangle (int x_, int y_, int width_, int height_)
858 , height (height_) {}
865 void setViewport (const RenderContext& renderCtx, const Rectangle& rect)
867 renderCtx.getFunctions().viewport(rect.x, rect.y, rect.width, rect.height);
870 void readRectangle (const RenderContext& renderCtx, const Rectangle& rect, Surface& dst)
872 dst.setSize(rect.width, rect.height);
873 glu::readPixels(renderCtx, rect.x, rect.y, dst.getAccess());
876 Rectangle randomViewport (const RenderContext& ctx, Random& rnd,
877 GLint maxWidth, GLint maxHeight)
879 const RenderTarget& target = ctx.getRenderTarget();
880 GLint width = de::min(target.getWidth(), maxWidth);
881 GLint xOff = rnd.getInt(0, target.getWidth() - width);
882 GLint height = de::min(target.getHeight(), maxHeight);
883 GLint yOff = rnd.getInt(0, target.getHeight() - height);
885 return Rectangle(xOff, yOff, width, height);
888 // SeparateShaderTest
890 class SeparateShaderTest : public TestCase, private CallLogWrapper
893 typedef void (SeparateShaderTest::*TestFunc)
894 (MovePtr<Pipeline>& pipeOut);
896 SeparateShaderTest (Context& ctx,
898 const string& description,
900 const TestParams& params,
903 IterateResult iterate (void);
905 void testPipelineRendering (MovePtr<Pipeline>& pipeOut);
906 void testCurrentProgPriority (MovePtr<Pipeline>& pipeOut);
907 void testActiveProgramUniform (MovePtr<Pipeline>& pipeOut);
908 void testPipelineQueryActive (MovePtr<Pipeline>& pipeOut);
909 void testPipelineQueryPrograms (MovePtr<Pipeline>& pipeOut);
913 const RenderContext& getRenderContext (void);
915 void setUniform (ProgramWrapper& program,
916 const string& uniformName,
920 void drawSurface (Surface& dst,
923 MovePtr<ProgramWrapper> createShaderProgram (const string* vtxSource,
924 const string* frgSource,
927 MovePtr<ProgramWrapper> createSingleShaderProgram (ShaderType shaderType,
930 MovePtr<Pipeline> createPipeline (const ProgramParams& pp);
932 MovePtr<ProgramWrapper> createReferenceProgram (const ProgramParams& pp);
935 int m_currentIteration;
939 ResultCollector m_status;
940 VaryingInterface m_varyings;
942 // Per-iteration state required for logging on exception
943 MovePtr<ProgramWrapper> m_fullProg;
944 MovePtr<ProgramWrapper> m_vtxProg;
945 MovePtr<ProgramWrapper> m_frgProg;
949 const RenderContext& SeparateShaderTest::getRenderContext (void)
951 return m_context.getRenderContext();
954 TestLog& SeparateShaderTest::log (void)
956 return m_testCtx.getLog();
959 SeparateShaderTest::SeparateShaderTest (Context& ctx,
961 const string& description,
963 const TestParams& params,
965 : TestCase (ctx, name.c_str(), description.c_str())
966 , CallLogWrapper (ctx.getRenderContext().getFunctions(), log())
967 , m_iterations (iterations)
968 , m_currentIteration(0)
970 , m_testFunc (testFunc)
971 , m_rnd (paramsSeed(params))
972 , m_status (log(), "// ")
973 , m_varyings (genVaryingInterface(params.varyings, m_rnd))
975 DE_ASSERT(paramsValid(params));
978 MovePtr<ProgramWrapper> SeparateShaderTest::createShaderProgram (const string* vtxSource,
979 const string* frgSource,
982 ProgramSources sources;
984 if (vtxSource != DE_NULL)
985 sources << VertexSource(*vtxSource);
986 if (frgSource != DE_NULL)
987 sources << FragmentSource(*frgSource);
988 sources << ProgramSeparable(separable);
990 MovePtr<ShaderProgramWrapper> wrapper (new ShaderProgramWrapper(getRenderContext(),
992 if (!wrapper->getShaderProgram().isOk())
994 log().writeMessage("Couldn't create shader program");
995 wrapper->writeToLog(log());
996 TCU_FAIL("Couldn't create shader program");
999 return MovePtr<ProgramWrapper>(wrapper.release());
1002 MovePtr<ProgramWrapper> SeparateShaderTest::createSingleShaderProgram (ShaderType shaderType,
1005 const RenderContext& renderCtx = getRenderContext();
1007 if (m_params.useCreateHelper)
1009 const char* const srcStr = src.c_str();
1010 const GLenum glType = glu::getGLShaderType(shaderType);
1011 const GLuint programName = glCreateShaderProgramv(glType, 1, &srcStr);
1013 if (glGetError() != GL_NO_ERROR || programName == 0)
1015 qpShaderType qpType = glu::getLogShaderType(shaderType);
1017 log() << TestLog::Message << "glCreateShaderProgramv() failed"
1018 << TestLog::EndMessage
1019 << TestLog::ShaderProgram(false, "[glCreateShaderProgramv() failed]")
1020 << TestLog::Shader(qpType, src,
1021 false, "[glCreateShaderProgramv() failed]")
1022 << TestLog::EndShaderProgram;
1023 TCU_FAIL("glCreateShaderProgramv() failed");
1026 RawProgramWrapper* const wrapper = new RawProgramWrapper(renderCtx, programName,
1028 MovePtr<ProgramWrapper> wrapperPtr(wrapper);
1029 Program& program = wrapper->getProgram();
1031 if (!program.getLinkStatus())
1033 log().writeMessage("glCreateShaderProgramv() failed at linking");
1034 wrapper->writeToLog(log());
1035 TCU_FAIL("glCreateShaderProgram() failed at linking");
1043 case glu::SHADERTYPE_VERTEX:
1044 return createShaderProgram(&src, DE_NULL, true);
1045 case glu::SHADERTYPE_FRAGMENT:
1046 return createShaderProgram(DE_NULL, &src, true);
1048 DE_ASSERT(!"Impossible case");
1051 return MovePtr<ProgramWrapper>(); // Shut up compiler warnings.
1054 void SeparateShaderTest::setUniform (ProgramWrapper& program,
1055 const string& uniformName,
1057 bool useProgramUniform)
1059 const GLuint progName = program.getProgramName();
1060 const GLint location = glGetUniformLocation(progName, uniformName.c_str());
1061 MessageBuilder msg = log().message();
1063 msg << "// Set program " << progName << "'s uniform '" << uniformName << "' to " << value;
1064 if (useProgramUniform)
1066 msg << " using glProgramUniform1f";
1067 glProgramUniform1f(progName, location, value);
1071 msg << " using glUseProgram and glUniform1f";
1072 glUseProgram(progName);
1073 glUniform1f(location, value);
1076 msg << TestLog::EndMessage;
1079 MovePtr<Pipeline> SeparateShaderTest::createPipeline(const ProgramParams& pp)
1081 const bool useUniform = m_params.useUniform;
1082 const string vtxName = m_params.useSameName ? "scale" : "vtxScale";
1083 const deUint32 initVtxSeed = m_params.switchVtx ? m_rnd.getUint32() : pp.vtxSeed;
1085 const string frgName = m_params.useSameName ? "scale" : "frgScale";
1086 const deUint32 initFrgSeed = m_params.switchFrg ? m_rnd.getUint32() : pp.frgSeed;
1087 const string frgSource = genFrgShaderSrc(initFrgSeed, m_varyings.frgInputs,
1088 frgName, useUniform, pp.frgScale);
1090 const RenderContext& renderCtx = getRenderContext();
1091 MovePtr<ProgramPipeline> pipeline (new ProgramPipeline(renderCtx));
1092 MovePtr<ProgramWrapper> fullProg;
1093 MovePtr<ProgramWrapper> vtxProg;
1094 MovePtr<ProgramWrapper> frgProg;
1096 // We cannot allow a situation where we have a single program with a
1097 // single uniform, because then the vertex and fragment shader uniforms
1098 // would not be distinct in the final pipeline, and we are going to test
1099 // that altering one uniform will not affect the other.
1100 DE_ASSERT(!(m_params.initSingle && m_params.useSameName &&
1101 !m_params.switchVtx && !m_params.switchFrg));
1103 if (m_params.initSingle)
1105 string vtxSource = genVtxShaderSrc(initVtxSeed,
1106 varyingCompatVtxOutputs(m_varyings),
1107 vtxName, useUniform, pp.vtxScale);
1108 fullProg = createShaderProgram(&vtxSource, &frgSource, true);
1109 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
1110 fullProg->getProgramName());
1111 log() << TestLog::Message
1112 << "// Created pipeline " << pipeline->getPipeline()
1113 << " with two-shader program " << fullProg->getProgramName()
1114 << TestLog::EndMessage;
1118 string vtxSource = genVtxShaderSrc(initVtxSeed, m_varyings.vtxOutputs,
1119 vtxName, useUniform, pp.vtxScale);
1120 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, vtxSource);
1121 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1123 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, frgSource);
1124 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1126 log() << TestLog::Message
1127 << "// Created pipeline " << pipeline->getPipeline()
1128 << " with vertex program " << vtxProg->getProgramName()
1129 << " and fragment program " << frgProg->getProgramName()
1130 << TestLog::EndMessage;
1133 m_status.check(pipeline->isValid(),
1134 "Pipeline is invalid after initialization");
1136 if (m_params.switchVtx)
1138 string newSource = genVtxShaderSrc(pp.vtxSeed, m_varyings.vtxOutputs,
1139 vtxName, useUniform, pp.vtxScale);
1140 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, newSource);
1141 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1142 log() << TestLog::Message
1143 << "// Switched pipeline " << pipeline->getPipeline()
1144 << "'s vertex stage to single-shader program " << vtxProg->getProgramName()
1145 << TestLog::EndMessage;
1147 if (m_params.switchFrg)
1149 string newSource = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs,
1150 frgName, useUniform, pp.frgScale);
1151 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, newSource);
1152 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1153 log() << TestLog::Message
1154 << "// Switched pipeline " << pipeline->getPipeline()
1155 << "'s fragment stage to single-shader program " << frgProg->getProgramName()
1156 << TestLog::EndMessage;
1159 if (m_params.switchVtx || m_params.switchFrg)
1160 m_status.check(pipeline->isValid(),
1161 "Pipeline became invalid after changing a stage's program");
1163 if (m_params.useUniform)
1165 ProgramWrapper& vtxStage = *(vtxProg ? vtxProg : fullProg);
1166 ProgramWrapper& frgStage = *(frgProg ? frgProg : fullProg);
1168 setUniform(vtxStage, vtxName, pp.vtxScale, m_params.useProgramUniform);
1169 setUniform(frgStage, frgName, pp.frgScale, m_params.useProgramUniform);
1172 log().writeMessage("// Programs use constants instead of uniforms");
1174 return MovePtr<Pipeline>(new Pipeline(pipeline, fullProg, vtxProg, frgProg));
1177 MovePtr<ProgramWrapper> SeparateShaderTest::createReferenceProgram(const ProgramParams& pp)
1179 bool useUniform = m_params.useUniform;
1180 const string vtxSrc = genVtxShaderSrc(pp.vtxSeed,
1181 varyingCompatVtxOutputs(m_varyings),
1182 "vtxScale", useUniform, pp.vtxScale);
1183 const string frgSrc = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs,
1184 "frgScale", useUniform, pp.frgScale);
1185 MovePtr<ProgramWrapper> program = createShaderProgram(&vtxSrc, &frgSrc, false);
1186 GLuint progName = program->getProgramName();
1188 log() << TestLog::Message
1189 << "// Created monolithic shader program " << progName
1190 << TestLog::EndMessage;
1194 setUniform(*program, "vtxScale", pp.vtxScale, false);
1195 setUniform(*program, "frgScale", pp.frgScale, false);
1201 void SeparateShaderTest::drawSurface (Surface& dst, deUint32 seed)
1203 const RenderContext& renderCtx = getRenderContext();
1204 Random rnd (seed > 0 ? seed : m_rnd.getUint32());
1205 Rectangle viewport = randomViewport(renderCtx, rnd,
1206 VIEWPORT_SIZE, VIEWPORT_SIZE);
1207 glClearColor(0.125f, 0.25f, 0.5f, 1.f);
1208 setViewport(renderCtx, viewport);
1209 glClear(GL_COLOR_BUFFER_BIT);
1210 GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
1211 readRectangle(renderCtx, viewport, dst);
1212 log().writeMessage("// Drew a triangle");
1215 void SeparateShaderTest::testPipelineRendering (MovePtr<Pipeline>& pipeOut)
1217 ProgramParams pp = genProgramParams(m_rnd);
1218 Pipeline& pipeline = *(pipeOut = createPipeline(pp));
1219 GLuint pipeName = pipeline.pipeline->getPipeline();
1220 UniquePtr<ProgramWrapper> refProgram (createReferenceProgram(pp));
1221 GLuint refProgName = refProgram->getProgramName();
1223 Surface pipelineSurface;
1224 GLuint drawSeed = m_rnd.getUint32();
1226 glUseProgram(refProgName);
1227 log() << TestLog::Message << "// Use program " << refProgName << TestLog::EndMessage;
1228 drawSurface(refSurface, drawSeed);
1231 glBindProgramPipeline(pipeName);
1232 log() << TestLog::Message << "// Bind pipeline " << pipeName << TestLog::EndMessage;
1233 drawSurface(pipelineSurface, drawSeed);
1234 glBindProgramPipeline(0);
1237 const bool result = tcu::fuzzyCompare(
1238 m_testCtx.getLog(), "Program pipeline result",
1239 "Result of comparing a program pipeline with a monolithic program",
1240 refSurface, pipelineSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1242 m_status.check(result, "Pipeline rendering differs from equivalent monolithic program");
1246 void SeparateShaderTest::testCurrentProgPriority (MovePtr<Pipeline>& pipeOut)
1248 ProgramParams pipePp = genProgramParams(m_rnd);
1249 ProgramParams programPp = genProgramParams(m_rnd);
1250 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1251 GLuint pipeName = pipeline.pipeline->getPipeline();
1252 UniquePtr<ProgramWrapper> program (createReferenceProgram(programPp));
1253 Surface pipelineSurface;
1255 Surface resultSurface;
1256 deUint32 drawSeed = m_rnd.getUint32();
1258 LOG_CALL(glBindProgramPipeline(pipeName));
1259 drawSurface(pipelineSurface, drawSeed);
1260 LOG_CALL(glBindProgramPipeline(0));
1262 LOG_CALL(glUseProgram(program->getProgramName()));
1263 drawSurface(refSurface, drawSeed);
1264 LOG_CALL(glUseProgram(0));
1266 LOG_CALL(glUseProgram(program->getProgramName()));
1267 LOG_CALL(glBindProgramPipeline(pipeName));
1268 drawSurface(resultSurface, drawSeed);
1269 LOG_CALL(glBindProgramPipeline(0));
1270 LOG_CALL(glUseProgram(0));
1272 bool result = tcu::pixelThresholdCompare(
1273 m_testCtx.getLog(), "Active program rendering result",
1274 "Active program rendering result",
1275 refSurface, resultSurface, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1277 m_status.check(result, "glBindProgramPipeline() affects glUseProgram()");
1279 log() << TestLog::Image("Pipeline image", "Image produced by pipeline",
1283 void SeparateShaderTest::testActiveProgramUniform (MovePtr<Pipeline>& pipeOut)
1285 ProgramParams refPp = genProgramParams(m_rnd);
1287 Surface resultSurface;
1288 deUint32 drawSeed = m_rnd.getUint32();
1292 UniquePtr<ProgramWrapper> refProg (createReferenceProgram(refPp));
1293 GLuint refProgName = refProg->getProgramName();
1295 glUseProgram(refProgName);
1296 log() << TestLog::Message << "// Use reference program " << refProgName
1297 << TestLog::EndMessage;
1298 drawSurface(refSurface, drawSeed);
1303 ProgramParams changePp = genProgramParams(m_rnd);
1304 changePp.vtxSeed = refPp.vtxSeed;
1305 changePp.frgSeed = refPp.frgSeed;
1306 UniquePtr<ProgramWrapper> changeProg (createReferenceProgram(changePp));
1307 GLuint changeName = changeProg->getProgramName();
1308 ProgramPipeline pipeline (getRenderContext());
1309 GLint vtxLoc = glGetUniformLocation(changeName, "vtxScale");
1310 GLint frgLoc = glGetUniformLocation(changeName, "frgScale");
1312 LOG_CALL(glBindProgramPipeline(pipeline.getPipeline()));
1314 pipeline.activeShaderProgram(changeName);
1315 log() << TestLog::Message << "// Set active shader program to " << changeName
1316 << TestLog::EndMessage;
1318 glUniform1f(vtxLoc, refPp.vtxScale);
1319 log() << TestLog::Message
1320 << "// Set uniform 'vtxScale' to " << refPp.vtxScale << " using glUniform1f"
1321 << TestLog::EndMessage;
1322 glUniform1f(frgLoc, refPp.frgScale);
1323 log() << TestLog::Message
1324 << "// Set uniform 'frgScale' to " << refPp.frgScale << " using glUniform1f"
1325 << TestLog::EndMessage;
1327 pipeline.activeShaderProgram(0);
1328 LOG_CALL(glBindProgramPipeline(0));
1330 LOG_CALL(glUseProgram(changeName));
1331 drawSurface(resultSurface, drawSeed);
1332 LOG_CALL(glUseProgram(0));
1335 bool result = tcu::fuzzyCompare(
1336 m_testCtx.getLog(), "Active program uniform result",
1337 "Active program uniform result",
1338 refSurface, resultSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1340 m_status.check(result,
1341 "glUniform() did not correctly modify "
1342 "the active program of the bound pipeline");
1345 void SeparateShaderTest::testPipelineQueryPrograms (MovePtr<Pipeline>& pipeOut)
1347 ProgramParams pipePp = genProgramParams(m_rnd);
1348 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1349 GLuint pipeName = pipeline.pipeline->getPipeline();
1353 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_VERTEX_SHADER, &queryVtx)));
1354 m_status.check(GLuint(queryVtx) == pipeline.getVertexProgram().getProgramName(),
1355 "Program pipeline query reported wrong vertex shader program");
1357 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_FRAGMENT_SHADER, &queryFrg)));
1358 m_status.check(GLuint(queryFrg) == pipeline.getFragmentProgram().getProgramName(),
1359 "Program pipeline query reported wrong fragment shader program");
1362 void SeparateShaderTest::testPipelineQueryActive (MovePtr<Pipeline>& pipeOut)
1364 ProgramParams pipePp = genProgramParams(m_rnd);
1365 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1366 GLuint pipeName = pipeline.pipeline->getPipeline();
1367 GLuint newActive = pipeline.getVertexProgram().getProgramName();
1368 GLint queryActive = 0;
1370 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1371 m_status.check(queryActive == 0,
1372 "Program pipeline query reported non-zero initial active program");
1374 pipeline.pipeline->activeShaderProgram(newActive);
1375 log() << TestLog::Message
1376 << "Set pipeline " << pipeName << "'s active shader program to " << newActive
1377 << TestLog::EndMessage;
1379 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1380 m_status.check(GLuint(queryActive) == newActive,
1381 "Program pipeline query reported incorrect active program");
1383 pipeline.pipeline->activeShaderProgram(0);
1386 TestCase::IterateResult SeparateShaderTest::iterate (void)
1388 MovePtr<Pipeline> pipeline;
1390 DE_ASSERT(m_iterations > 0);
1392 if (m_currentIteration == 0)
1393 logParams(log(), m_params);
1395 ++m_currentIteration;
1399 (this->*m_testFunc)(pipeline);
1400 log().writeMessage("");
1402 catch (const tcu::Exception&)
1405 logPipeline(log(), *pipeline);
1409 if (m_status.getResult() != QP_TEST_RESULT_PASS)
1412 logPipeline(log(), *pipeline);
1414 else if (m_currentIteration < m_iterations)
1417 m_status.setTestContextResult(m_testCtx);
1421 // Group construction utilities
1425 PARAMFLAGS_SWITCH_FRAGMENT = 1 << 0,
1426 PARAMFLAGS_SWITCH_VERTEX = 1 << 1,
1427 PARAMFLAGS_INIT_SINGLE = 1 << 2,
1428 PARAMFLAGS_LAST = 1 << 3,
1429 PARAMFLAGS_MASK = PARAMFLAGS_LAST - 1
1432 bool areCaseParamFlagsValid (ParamFlags flags)
1434 const ParamFlags switchAll = ParamFlags(PARAMFLAGS_SWITCH_VERTEX|PARAMFLAGS_SWITCH_FRAGMENT);
1436 if ((flags & PARAMFLAGS_INIT_SINGLE) != 0)
1437 return (flags & switchAll) == 0 ||
1438 (flags & switchAll) == switchAll;
1443 bool addRenderTest (TestCaseGroup& group, const string& namePrefix, const string& descPrefix,
1444 int numIterations, ParamFlags flags, TestParams params)
1449 DE_ASSERT(areCaseParamFlagsValid(flags));
1454 params.initSingle = (flags & PARAMFLAGS_INIT_SINGLE) != 0;
1455 params.switchVtx = (flags & PARAMFLAGS_SWITCH_VERTEX) != 0;
1456 params.switchFrg = (flags & PARAMFLAGS_SWITCH_FRAGMENT) != 0;
1458 name << (flags & PARAMFLAGS_INIT_SINGLE ? "single_program" : "separate_programs");
1459 desc << (flags & PARAMFLAGS_INIT_SINGLE
1460 ? "Single program with two shaders"
1461 : "Separate programs for each shader");
1463 switch (flags & (PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX))
1467 case PARAMFLAGS_SWITCH_FRAGMENT:
1468 name << "_add_fragment";
1469 desc << ", then add a fragment program";
1471 case PARAMFLAGS_SWITCH_VERTEX:
1472 name << "_add_vertex";
1473 desc << ", then add a vertex program";
1475 case PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX:
1476 name << "_add_both";
1477 desc << ", then add both vertex and shader programs";
1481 if (!paramsValid(params))
1484 group.addChild(new SeparateShaderTest(group.getContext(), name.str(), desc.str(),
1485 numIterations, params,
1486 &SeparateShaderTest::testPipelineRendering));
1491 void describeInterpolation(const string& stage, Interpolation qual,
1492 ostringstream& name, ostringstream& desc)
1494 if (qual == glu::INTERPOLATION_LAST)
1496 desc << ", unqualified in " << stage << " shader";
1501 const string qualName = glu::getInterpolationName(qual);
1503 name << "_" << stage << "_" << qualName;
1504 desc << ", qualified '" << qualName << "' in " << stage << " shader";
1509 } // anonymous namespace
1511 TestCaseGroup* createSeparateShaderTests (Context& ctx)
1513 TestParams defaultParams;
1514 int numIterations = 4;
1515 TestCaseGroup* group =
1516 new TestCaseGroup(ctx, "separate_shader", "Separate shader tests");
1518 defaultParams.useUniform = false;
1519 defaultParams.initSingle = false;
1520 defaultParams.switchVtx = false;
1521 defaultParams.switchFrg = false;
1522 defaultParams.useCreateHelper = false;
1523 defaultParams.useProgramUniform = false;
1524 defaultParams.useSameName = false;
1525 defaultParams.varyings.count = 0;
1526 defaultParams.varyings.type = glu::TYPE_INVALID;
1527 defaultParams.varyings.binding = BINDING_NAME;
1528 defaultParams.varyings.vtxInterp = glu::INTERPOLATION_LAST;
1529 defaultParams.varyings.frgInterp = glu::INTERPOLATION_LAST;
1531 TestCaseGroup* stagesGroup =
1532 new TestCaseGroup(ctx, "pipeline", "Pipeline configuration tests");
1533 group->addChild(stagesGroup);
1535 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST << 2; ++flags)
1537 TestParams params = defaultParams;
1541 if (!areCaseParamFlagsValid(ParamFlags(flags & PARAMFLAGS_MASK)))
1544 if (flags & (PARAMFLAGS_LAST << 1))
1546 params.useSameName = true;
1548 desc << "Identically named ";
1552 name << "different_";
1553 desc << "Differently named ";
1556 if (flags & PARAMFLAGS_LAST)
1558 params.useUniform = true;
1560 desc << "uniforms, ";
1564 name << "constant_";
1565 desc << "constants, ";
1568 addRenderTest(*stagesGroup, name.str(), desc.str(), numIterations,
1569 ParamFlags(flags & PARAMFLAGS_MASK), params);
1572 TestCaseGroup* programUniformGroup =
1573 new TestCaseGroup(ctx, "program_uniform", "ProgramUniform tests");
1574 group->addChild(programUniformGroup);
1576 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1578 TestParams params = defaultParams;
1580 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1583 params.useUniform = true;
1584 params.useProgramUniform = true;
1586 addRenderTest(*programUniformGroup, "", "", numIterations, ParamFlags(flags), params);
1589 TestCaseGroup* createShaderProgramGroup =
1590 new TestCaseGroup(ctx, "create_shader_program", "CreateShaderProgram tests");
1591 group->addChild(createShaderProgramGroup);
1593 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1595 TestParams params = defaultParams;
1597 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1600 params.useCreateHelper = true;
1602 addRenderTest(*createShaderProgramGroup, "", "", numIterations,
1603 ParamFlags(flags), params);
1606 TestCaseGroup* interfaceGroup =
1607 new TestCaseGroup(ctx, "interface", "Shader interface compatibility tests");
1608 group->addChild(interfaceGroup);
1612 NUM_INTERPOLATIONS = glu::INTERPOLATION_LAST + 1, // INTERPOLATION_LAST is valid
1613 INTERFACEFLAGS_LAST = BINDING_LAST * NUM_INTERPOLATIONS * NUM_INTERPOLATIONS
1616 for (deUint32 flags = 0; flags < INTERFACEFLAGS_LAST; ++flags)
1618 deUint32 tmpFlags = flags;
1619 Interpolation frgInterp = Interpolation(tmpFlags % NUM_INTERPOLATIONS);
1620 Interpolation vtxInterp = Interpolation((tmpFlags /= NUM_INTERPOLATIONS)
1621 % NUM_INTERPOLATIONS);
1622 BindingKind binding = BindingKind((tmpFlags /= NUM_INTERPOLATIONS)
1624 TestParams params = defaultParams;
1628 params.varyings.count = 1;
1629 params.varyings.type = glu::TYPE_FLOAT;
1630 params.varyings.binding = binding;
1631 params.varyings.vtxInterp = vtxInterp;
1632 params.varyings.frgInterp = frgInterp;
1636 case BINDING_LOCATION:
1637 name << "same_location";
1638 desc << "Varyings have same location, ";
1641 name << "same_name";
1642 desc << "Varyings have same name, ";
1645 DE_ASSERT(!"Impossible");
1648 describeInterpolation("vertex", vtxInterp, name, desc);
1649 describeInterpolation("fragment", frgInterp, name, desc);
1651 if (!paramsValid(params))
1654 interfaceGroup->addChild(
1655 new SeparateShaderTest(ctx, name.str(), desc.str(), numIterations, params,
1656 &SeparateShaderTest::testPipelineRendering));
1659 deUint32 baseSeed = ctx.getTestContext().getCommandLine().getBaseSeed();
1660 Random rnd (deStringHash("separate_shader.random") + baseSeed);
1662 TestCaseGroup* randomGroup = new TestCaseGroup(
1663 ctx, "random", "Random pipeline configuration tests");
1664 group->addChild(randomGroup);
1666 for (deUint32 i = 0; i < 128; ++i)
1670 deUint32 genIterations = 4096;
1674 params = genParams(rnd.getUint32());
1675 code = paramsCode(params);
1676 } while (de::contains(seen, code) && --genIterations > 0);
1680 string name = de::toString(i); // Would be code but baseSeed can change
1682 randomGroup->addChild(new SeparateShaderTest(
1683 ctx, name, name, numIterations, params,
1684 &SeparateShaderTest::testPipelineRendering));
1687 TestCaseGroup* apiGroup =
1688 new TestCaseGroup(ctx, "api", "Program pipeline API tests");
1689 group->addChild(apiGroup);
1692 // More or less random parameters. These shouldn't have much effect, so just
1693 // do a single sample.
1694 TestParams params = defaultParams;
1695 params.useUniform = true;
1696 apiGroup->addChild(new SeparateShaderTest(
1698 "current_program_priority",
1699 "Test priority between current program and pipeline binding",
1700 1, params, &SeparateShaderTest::testCurrentProgPriority));
1701 apiGroup->addChild(new SeparateShaderTest(
1703 "active_program_uniform",
1704 "Test that glUniform() affects a pipeline's active program",
1705 1, params, &SeparateShaderTest::testActiveProgramUniform));
1707 apiGroup->addChild(new SeparateShaderTest(
1709 "pipeline_programs",
1710 "Test queries for programs in program pipeline stages",
1711 1, params, &SeparateShaderTest::testPipelineQueryPrograms));
1713 apiGroup->addChild(new SeparateShaderTest(
1716 "Test query for active programs in a program pipeline",
1717 1, params, &SeparateShaderTest::testPipelineQueryActive));
1720 TestCaseGroup* interfaceMismatchGroup =
1721 new TestCaseGroup(ctx, "validation", "Negative program pipeline interface matching");
1722 group->addChild(interfaceMismatchGroup);
1725 gls::ShaderLibrary shaderLibrary (ctx.getTestContext(), ctx.getRenderContext(), ctx.getContextInfo());
1726 const std::vector<tcu::TestNode*> children = shaderLibrary.loadShaderFile("shaders/separate_shader_validation.test");
1728 for (int i = 0; i < (int)children.size(); i++)
1729 interfaceMismatchGroup->addChild(children[i]);