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))
695 // Mismatch by flat / smooth is not allowed. See Khronos bug #12630
696 if ((params.varyings.vtxInterp == INTERPOLATION_FLAT) != (params.varyings.frgInterp == INTERPOLATION_FLAT))
702 void logParams (TestLog& log, const TestParams& params)
704 // We don't log operational details here since those are shown
705 // in the log messages during execution.
706 MessageBuilder msg = log.message();
708 msg << "Pipeline configuration:\n";
710 msg << "Vertex and fragment shaders have "
711 << (params.useUniform ? "uniform" : "constant") << "s with "
712 << (params.useSameName ? "the same name" : "different names") << ".\n";
714 if (params.varyings.count == 0)
715 msg << "There are no varyings.\n";
718 if (params.varyings.count == 1)
719 msg << "There is one varying.\n";
721 msg << "There are " << params.varyings.count << " varyings.\n";
723 if (params.varyings.type == glu::TYPE_LAST)
724 msg << "Varyings are of random types.\n";
726 msg << "Varyings are of type '"
727 << glu::getDataTypeName(params.varyings.type) << "'.\n";
729 msg << "Varying outputs and inputs correspond ";
730 switch (params.varyings.binding)
735 case BINDING_LOCATION:
736 msg << "by location.\n";
739 msg << "randomly either by name or by location.\n";
742 DE_ASSERT(!"Impossible");
745 msg << "In the vertex shader the varyings are qualified ";
746 if (params.varyings.vtxInterp == glu::INTERPOLATION_LAST)
747 msg << "with a random interpolation qualifier.\n";
749 msg << "'" << glu::getInterpolationName(params.varyings.vtxInterp) << "'.\n";
751 msg << "In the fragment shader the varyings are qualified ";
752 if (params.varyings.frgInterp == glu::INTERPOLATION_LAST)
753 msg << "with a random interpolation qualifier.\n";
755 msg << "'" << glu::getInterpolationName(params.varyings.frgInterp) << "'.\n";
758 msg << TestLog::EndMessage;
760 log.writeMessage("");
763 TestParams genParams (deUint32 seed)
771 params.initSingle = rnd.getBool();
772 params.switchVtx = rnd.getBool();
773 params.switchFrg = rnd.getBool();
774 params.useUniform = rnd.getBool();
775 params.useProgramUniform = params.useUniform && rnd.getBool();
776 params.useCreateHelper = rnd.getBool();
777 params.useSameName = rnd.getBool();
779 int i = rnd.getInt(-1, 3);
780 params.varyings.count = (i == -1 ? 0 : 1 << i);
782 if (params.varyings.count > 0)
784 params.varyings.type = glu::TYPE_LAST;
785 params.varyings.binding = BINDING_LAST;
786 params.varyings.vtxInterp = glu::INTERPOLATION_LAST;
787 params.varyings.frgInterp = glu::INTERPOLATION_LAST;
791 params.varyings.type = glu::TYPE_INVALID;
792 params.varyings.binding = BINDING_LAST;
793 params.varyings.vtxInterp = glu::INTERPOLATION_LAST;
794 params.varyings.frgInterp = glu::INTERPOLATION_LAST;
798 } while (!paramsValid(params) && tryNdx < 16);
800 DE_ASSERT(paramsValid(params));
805 // Program pipeline wrapper that retains references to component programs.
809 Pipeline (MovePtr<ProgramPipeline> pipeline_,
810 MovePtr<ProgramWrapper> fullProg_,
811 MovePtr<ProgramWrapper> vtxProg_,
812 MovePtr<ProgramWrapper> frgProg_)
813 : pipeline (pipeline_)
814 , fullProg (fullProg_)
816 , frgProg (frgProg_) {}
818 ProgramWrapper& getVertexProgram (void) const
820 return vtxProg ? *vtxProg : *fullProg;
823 ProgramWrapper& getFragmentProgram (void) const
825 return frgProg ? *frgProg : *fullProg;
828 UniquePtr<ProgramPipeline> pipeline;
829 UniquePtr<ProgramWrapper> fullProg;
830 UniquePtr<ProgramWrapper> vtxProg;
831 UniquePtr<ProgramWrapper> frgProg;
834 void logPipeline(TestLog& log, const Pipeline& pipeline)
836 ProgramWrapper& vtxProg = pipeline.getVertexProgram();
837 ProgramWrapper& frgProg = pipeline.getFragmentProgram();
839 log.writeMessage("// Failed program pipeline:");
840 if (&vtxProg == &frgProg)
842 log.writeMessage("// Common program for both vertex and fragment stages:");
843 vtxProg.writeToLog(log);
847 log.writeMessage("// Vertex stage program:");
848 vtxProg.writeToLog(log);
849 log.writeMessage("// Fragment stage program:");
850 frgProg.writeToLog(log);
858 Rectangle (int x_, int y_, int width_, int height_)
862 , height (height_) {}
869 void setViewport (const RenderContext& renderCtx, const Rectangle& rect)
871 renderCtx.getFunctions().viewport(rect.x, rect.y, rect.width, rect.height);
874 void readRectangle (const RenderContext& renderCtx, const Rectangle& rect, Surface& dst)
876 dst.setSize(rect.width, rect.height);
877 glu::readPixels(renderCtx, rect.x, rect.y, dst.getAccess());
880 Rectangle randomViewport (const RenderContext& ctx, Random& rnd,
881 GLint maxWidth, GLint maxHeight)
883 const RenderTarget& target = ctx.getRenderTarget();
884 GLint width = de::min(target.getWidth(), maxWidth);
885 GLint xOff = rnd.getInt(0, target.getWidth() - width);
886 GLint height = de::min(target.getHeight(), maxHeight);
887 GLint yOff = rnd.getInt(0, target.getHeight() - height);
889 return Rectangle(xOff, yOff, width, height);
892 // SeparateShaderTest
894 class SeparateShaderTest : public TestCase, private CallLogWrapper
897 typedef void (SeparateShaderTest::*TestFunc)
898 (MovePtr<Pipeline>& pipeOut);
900 SeparateShaderTest (Context& ctx,
902 const string& description,
904 const TestParams& params,
907 IterateResult iterate (void);
909 void testPipelineRendering (MovePtr<Pipeline>& pipeOut);
910 void testCurrentProgPriority (MovePtr<Pipeline>& pipeOut);
911 void testActiveProgramUniform (MovePtr<Pipeline>& pipeOut);
912 void testPipelineQueryActive (MovePtr<Pipeline>& pipeOut);
913 void testPipelineQueryPrograms (MovePtr<Pipeline>& pipeOut);
917 const RenderContext& getRenderContext (void);
919 void setUniform (ProgramWrapper& program,
920 const string& uniformName,
924 void drawSurface (Surface& dst,
927 MovePtr<ProgramWrapper> createShaderProgram (const string* vtxSource,
928 const string* frgSource,
931 MovePtr<ProgramWrapper> createSingleShaderProgram (ShaderType shaderType,
934 MovePtr<Pipeline> createPipeline (const ProgramParams& pp);
936 MovePtr<ProgramWrapper> createReferenceProgram (const ProgramParams& pp);
939 int m_currentIteration;
943 ResultCollector m_status;
944 VaryingInterface m_varyings;
946 // Per-iteration state required for logging on exception
947 MovePtr<ProgramWrapper> m_fullProg;
948 MovePtr<ProgramWrapper> m_vtxProg;
949 MovePtr<ProgramWrapper> m_frgProg;
953 const RenderContext& SeparateShaderTest::getRenderContext (void)
955 return m_context.getRenderContext();
958 TestLog& SeparateShaderTest::log (void)
960 return m_testCtx.getLog();
963 SeparateShaderTest::SeparateShaderTest (Context& ctx,
965 const string& description,
967 const TestParams& params,
969 : TestCase (ctx, name.c_str(), description.c_str())
970 , CallLogWrapper (ctx.getRenderContext().getFunctions(), log())
971 , m_iterations (iterations)
972 , m_currentIteration(0)
974 , m_testFunc (testFunc)
975 , m_rnd (paramsSeed(params))
976 , m_status (log(), "// ")
977 , m_varyings (genVaryingInterface(params.varyings, m_rnd))
979 DE_ASSERT(paramsValid(params));
982 MovePtr<ProgramWrapper> SeparateShaderTest::createShaderProgram (const string* vtxSource,
983 const string* frgSource,
986 ProgramSources sources;
988 if (vtxSource != DE_NULL)
989 sources << VertexSource(*vtxSource);
990 if (frgSource != DE_NULL)
991 sources << FragmentSource(*frgSource);
992 sources << ProgramSeparable(separable);
994 MovePtr<ShaderProgramWrapper> wrapper (new ShaderProgramWrapper(getRenderContext(),
996 if (!wrapper->getShaderProgram().isOk())
998 log().writeMessage("Couldn't create shader program");
999 wrapper->writeToLog(log());
1000 TCU_FAIL("Couldn't create shader program");
1003 return MovePtr<ProgramWrapper>(wrapper.release());
1006 MovePtr<ProgramWrapper> SeparateShaderTest::createSingleShaderProgram (ShaderType shaderType,
1009 const RenderContext& renderCtx = getRenderContext();
1011 if (m_params.useCreateHelper)
1013 const char* const srcStr = src.c_str();
1014 const GLenum glType = glu::getGLShaderType(shaderType);
1015 const GLuint programName = glCreateShaderProgramv(glType, 1, &srcStr);
1017 if (glGetError() != GL_NO_ERROR || programName == 0)
1019 qpShaderType qpType = glu::getLogShaderType(shaderType);
1021 log() << TestLog::Message << "glCreateShaderProgramv() failed"
1022 << TestLog::EndMessage
1023 << TestLog::ShaderProgram(false, "[glCreateShaderProgramv() failed]")
1024 << TestLog::Shader(qpType, src,
1025 false, "[glCreateShaderProgramv() failed]")
1026 << TestLog::EndShaderProgram;
1027 TCU_FAIL("glCreateShaderProgramv() failed");
1030 RawProgramWrapper* const wrapper = new RawProgramWrapper(renderCtx, programName,
1032 MovePtr<ProgramWrapper> wrapperPtr(wrapper);
1033 Program& program = wrapper->getProgram();
1035 if (!program.getLinkStatus())
1037 log().writeMessage("glCreateShaderProgramv() failed at linking");
1038 wrapper->writeToLog(log());
1039 TCU_FAIL("glCreateShaderProgram() failed at linking");
1047 case glu::SHADERTYPE_VERTEX:
1048 return createShaderProgram(&src, DE_NULL, true);
1049 case glu::SHADERTYPE_FRAGMENT:
1050 return createShaderProgram(DE_NULL, &src, true);
1052 DE_ASSERT(!"Impossible case");
1055 return MovePtr<ProgramWrapper>(); // Shut up compiler warnings.
1058 void SeparateShaderTest::setUniform (ProgramWrapper& program,
1059 const string& uniformName,
1061 bool useProgramUniform)
1063 const GLuint progName = program.getProgramName();
1064 const GLint location = glGetUniformLocation(progName, uniformName.c_str());
1065 MessageBuilder msg = log().message();
1067 msg << "// Set program " << progName << "'s uniform '" << uniformName << "' to " << value;
1068 if (useProgramUniform)
1070 msg << " using glProgramUniform1f";
1071 glProgramUniform1f(progName, location, value);
1075 msg << " using glUseProgram and glUniform1f";
1076 glUseProgram(progName);
1077 glUniform1f(location, value);
1080 msg << TestLog::EndMessage;
1083 MovePtr<Pipeline> SeparateShaderTest::createPipeline(const ProgramParams& pp)
1085 const bool useUniform = m_params.useUniform;
1086 const string vtxName = m_params.useSameName ? "scale" : "vtxScale";
1087 const deUint32 initVtxSeed = m_params.switchVtx ? m_rnd.getUint32() : pp.vtxSeed;
1089 const string frgName = m_params.useSameName ? "scale" : "frgScale";
1090 const deUint32 initFrgSeed = m_params.switchFrg ? m_rnd.getUint32() : pp.frgSeed;
1091 const string frgSource = genFrgShaderSrc(initFrgSeed, m_varyings.frgInputs,
1092 frgName, useUniform, pp.frgScale);
1094 const RenderContext& renderCtx = getRenderContext();
1095 MovePtr<ProgramPipeline> pipeline (new ProgramPipeline(renderCtx));
1096 MovePtr<ProgramWrapper> fullProg;
1097 MovePtr<ProgramWrapper> vtxProg;
1098 MovePtr<ProgramWrapper> frgProg;
1100 // We cannot allow a situation where we have a single program with a
1101 // single uniform, because then the vertex and fragment shader uniforms
1102 // would not be distinct in the final pipeline, and we are going to test
1103 // that altering one uniform will not affect the other.
1104 DE_ASSERT(!(m_params.initSingle && m_params.useSameName &&
1105 !m_params.switchVtx && !m_params.switchFrg));
1107 if (m_params.initSingle)
1109 string vtxSource = genVtxShaderSrc(initVtxSeed,
1110 varyingCompatVtxOutputs(m_varyings),
1111 vtxName, useUniform, pp.vtxScale);
1112 fullProg = createShaderProgram(&vtxSource, &frgSource, true);
1113 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
1114 fullProg->getProgramName());
1115 log() << TestLog::Message
1116 << "// Created pipeline " << pipeline->getPipeline()
1117 << " with two-shader program " << fullProg->getProgramName()
1118 << TestLog::EndMessage;
1122 string vtxSource = genVtxShaderSrc(initVtxSeed, m_varyings.vtxOutputs,
1123 vtxName, useUniform, pp.vtxScale);
1124 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, vtxSource);
1125 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1127 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, frgSource);
1128 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1130 log() << TestLog::Message
1131 << "// Created pipeline " << pipeline->getPipeline()
1132 << " with vertex program " << vtxProg->getProgramName()
1133 << " and fragment program " << frgProg->getProgramName()
1134 << TestLog::EndMessage;
1137 m_status.check(pipeline->isValid(),
1138 "Pipeline is invalid after initialization");
1140 if (m_params.switchVtx)
1142 string newSource = genVtxShaderSrc(pp.vtxSeed, m_varyings.vtxOutputs,
1143 vtxName, useUniform, pp.vtxScale);
1144 vtxProg = createSingleShaderProgram(glu::SHADERTYPE_VERTEX, newSource);
1145 pipeline->useProgramStages(GL_VERTEX_SHADER_BIT, vtxProg->getProgramName());
1146 log() << TestLog::Message
1147 << "// Switched pipeline " << pipeline->getPipeline()
1148 << "'s vertex stage to single-shader program " << vtxProg->getProgramName()
1149 << TestLog::EndMessage;
1151 if (m_params.switchFrg)
1153 string newSource = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs,
1154 frgName, useUniform, pp.frgScale);
1155 frgProg = createSingleShaderProgram(glu::SHADERTYPE_FRAGMENT, newSource);
1156 pipeline->useProgramStages(GL_FRAGMENT_SHADER_BIT, frgProg->getProgramName());
1157 log() << TestLog::Message
1158 << "// Switched pipeline " << pipeline->getPipeline()
1159 << "'s fragment stage to single-shader program " << frgProg->getProgramName()
1160 << TestLog::EndMessage;
1163 if (m_params.switchVtx || m_params.switchFrg)
1164 m_status.check(pipeline->isValid(),
1165 "Pipeline became invalid after changing a stage's program");
1167 if (m_params.useUniform)
1169 ProgramWrapper& vtxStage = *(vtxProg ? vtxProg : fullProg);
1170 ProgramWrapper& frgStage = *(frgProg ? frgProg : fullProg);
1172 setUniform(vtxStage, vtxName, pp.vtxScale, m_params.useProgramUniform);
1173 setUniform(frgStage, frgName, pp.frgScale, m_params.useProgramUniform);
1176 log().writeMessage("// Programs use constants instead of uniforms");
1178 return MovePtr<Pipeline>(new Pipeline(pipeline, fullProg, vtxProg, frgProg));
1181 MovePtr<ProgramWrapper> SeparateShaderTest::createReferenceProgram(const ProgramParams& pp)
1183 bool useUniform = m_params.useUniform;
1184 const string vtxSrc = genVtxShaderSrc(pp.vtxSeed,
1185 varyingCompatVtxOutputs(m_varyings),
1186 "vtxScale", useUniform, pp.vtxScale);
1187 const string frgSrc = genFrgShaderSrc(pp.frgSeed, m_varyings.frgInputs,
1188 "frgScale", useUniform, pp.frgScale);
1189 MovePtr<ProgramWrapper> program = createShaderProgram(&vtxSrc, &frgSrc, false);
1190 GLuint progName = program->getProgramName();
1192 log() << TestLog::Message
1193 << "// Created monolithic shader program " << progName
1194 << TestLog::EndMessage;
1198 setUniform(*program, "vtxScale", pp.vtxScale, false);
1199 setUniform(*program, "frgScale", pp.frgScale, false);
1205 void SeparateShaderTest::drawSurface (Surface& dst, deUint32 seed)
1207 const RenderContext& renderCtx = getRenderContext();
1208 Random rnd (seed > 0 ? seed : m_rnd.getUint32());
1209 Rectangle viewport = randomViewport(renderCtx, rnd,
1210 VIEWPORT_SIZE, VIEWPORT_SIZE);
1211 glClearColor(0.125f, 0.25f, 0.5f, 1.f);
1212 setViewport(renderCtx, viewport);
1213 glClear(GL_COLOR_BUFFER_BIT);
1214 GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
1215 readRectangle(renderCtx, viewport, dst);
1216 log().writeMessage("// Drew a triangle");
1219 void SeparateShaderTest::testPipelineRendering (MovePtr<Pipeline>& pipeOut)
1221 ProgramParams pp = genProgramParams(m_rnd);
1222 Pipeline& pipeline = *(pipeOut = createPipeline(pp));
1223 GLuint pipeName = pipeline.pipeline->getPipeline();
1224 UniquePtr<ProgramWrapper> refProgram (createReferenceProgram(pp));
1225 GLuint refProgName = refProgram->getProgramName();
1227 Surface pipelineSurface;
1228 GLuint drawSeed = m_rnd.getUint32();
1230 glUseProgram(refProgName);
1231 log() << TestLog::Message << "// Use program " << refProgName << TestLog::EndMessage;
1232 drawSurface(refSurface, drawSeed);
1235 glBindProgramPipeline(pipeName);
1236 log() << TestLog::Message << "// Bind pipeline " << pipeName << TestLog::EndMessage;
1237 drawSurface(pipelineSurface, drawSeed);
1238 glBindProgramPipeline(0);
1241 const bool result = tcu::fuzzyCompare(
1242 m_testCtx.getLog(), "Program pipeline result",
1243 "Result of comparing a program pipeline with a monolithic program",
1244 refSurface, pipelineSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1246 m_status.check(result, "Pipeline rendering differs from equivalent monolithic program");
1250 void SeparateShaderTest::testCurrentProgPriority (MovePtr<Pipeline>& pipeOut)
1252 ProgramParams pipePp = genProgramParams(m_rnd);
1253 ProgramParams programPp = genProgramParams(m_rnd);
1254 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1255 GLuint pipeName = pipeline.pipeline->getPipeline();
1256 UniquePtr<ProgramWrapper> program (createReferenceProgram(programPp));
1257 Surface pipelineSurface;
1259 Surface resultSurface;
1260 deUint32 drawSeed = m_rnd.getUint32();
1262 LOG_CALL(glBindProgramPipeline(pipeName));
1263 drawSurface(pipelineSurface, drawSeed);
1264 LOG_CALL(glBindProgramPipeline(0));
1266 LOG_CALL(glUseProgram(program->getProgramName()));
1267 drawSurface(refSurface, drawSeed);
1268 LOG_CALL(glUseProgram(0));
1270 LOG_CALL(glUseProgram(program->getProgramName()));
1271 LOG_CALL(glBindProgramPipeline(pipeName));
1272 drawSurface(resultSurface, drawSeed);
1273 LOG_CALL(glBindProgramPipeline(0));
1274 LOG_CALL(glUseProgram(0));
1276 bool result = tcu::pixelThresholdCompare(
1277 m_testCtx.getLog(), "Active program rendering result",
1278 "Active program rendering result",
1279 refSurface, resultSurface, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
1281 m_status.check(result, "glBindProgramPipeline() affects glUseProgram()");
1283 log() << TestLog::Image("Pipeline image", "Image produced by pipeline",
1287 void SeparateShaderTest::testActiveProgramUniform (MovePtr<Pipeline>& pipeOut)
1289 ProgramParams refPp = genProgramParams(m_rnd);
1291 Surface resultSurface;
1292 deUint32 drawSeed = m_rnd.getUint32();
1296 UniquePtr<ProgramWrapper> refProg (createReferenceProgram(refPp));
1297 GLuint refProgName = refProg->getProgramName();
1299 glUseProgram(refProgName);
1300 log() << TestLog::Message << "// Use reference program " << refProgName
1301 << TestLog::EndMessage;
1302 drawSurface(refSurface, drawSeed);
1307 ProgramParams changePp = genProgramParams(m_rnd);
1308 changePp.vtxSeed = refPp.vtxSeed;
1309 changePp.frgSeed = refPp.frgSeed;
1310 UniquePtr<ProgramWrapper> changeProg (createReferenceProgram(changePp));
1311 GLuint changeName = changeProg->getProgramName();
1312 ProgramPipeline pipeline (getRenderContext());
1313 GLint vtxLoc = glGetUniformLocation(changeName, "vtxScale");
1314 GLint frgLoc = glGetUniformLocation(changeName, "frgScale");
1316 LOG_CALL(glBindProgramPipeline(pipeline.getPipeline()));
1318 pipeline.activeShaderProgram(changeName);
1319 log() << TestLog::Message << "// Set active shader program to " << changeName
1320 << TestLog::EndMessage;
1322 glUniform1f(vtxLoc, refPp.vtxScale);
1323 log() << TestLog::Message
1324 << "// Set uniform 'vtxScale' to " << refPp.vtxScale << " using glUniform1f"
1325 << TestLog::EndMessage;
1326 glUniform1f(frgLoc, refPp.frgScale);
1327 log() << TestLog::Message
1328 << "// Set uniform 'frgScale' to " << refPp.frgScale << " using glUniform1f"
1329 << TestLog::EndMessage;
1331 pipeline.activeShaderProgram(0);
1332 LOG_CALL(glBindProgramPipeline(0));
1334 LOG_CALL(glUseProgram(changeName));
1335 drawSurface(resultSurface, drawSeed);
1336 LOG_CALL(glUseProgram(0));
1339 bool result = tcu::fuzzyCompare(
1340 m_testCtx.getLog(), "Active program uniform result",
1341 "Active program uniform result",
1342 refSurface, resultSurface, 0.05f, tcu::COMPARE_LOG_RESULT);
1344 m_status.check(result,
1345 "glUniform() did not correctly modify "
1346 "the active program of the bound pipeline");
1349 void SeparateShaderTest::testPipelineQueryPrograms (MovePtr<Pipeline>& pipeOut)
1351 ProgramParams pipePp = genProgramParams(m_rnd);
1352 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1353 GLuint pipeName = pipeline.pipeline->getPipeline();
1357 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_VERTEX_SHADER, &queryVtx)));
1358 m_status.check(GLuint(queryVtx) == pipeline.getVertexProgram().getProgramName(),
1359 "Program pipeline query reported wrong vertex shader program");
1361 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_FRAGMENT_SHADER, &queryFrg)));
1362 m_status.check(GLuint(queryFrg) == pipeline.getFragmentProgram().getProgramName(),
1363 "Program pipeline query reported wrong fragment shader program");
1366 void SeparateShaderTest::testPipelineQueryActive (MovePtr<Pipeline>& pipeOut)
1368 ProgramParams pipePp = genProgramParams(m_rnd);
1369 Pipeline& pipeline = *(pipeOut = createPipeline(pipePp));
1370 GLuint pipeName = pipeline.pipeline->getPipeline();
1371 GLuint newActive = pipeline.getVertexProgram().getProgramName();
1372 GLint queryActive = 0;
1374 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1375 m_status.check(queryActive == 0,
1376 "Program pipeline query reported non-zero initial active program");
1378 pipeline.pipeline->activeShaderProgram(newActive);
1379 log() << TestLog::Message
1380 << "Set pipeline " << pipeName << "'s active shader program to " << newActive
1381 << TestLog::EndMessage;
1383 LOG_CALL(GLU_CHECK_CALL(glGetProgramPipelineiv(pipeName, GL_ACTIVE_PROGRAM, &queryActive)));
1384 m_status.check(GLuint(queryActive) == newActive,
1385 "Program pipeline query reported incorrect active program");
1387 pipeline.pipeline->activeShaderProgram(0);
1390 TestCase::IterateResult SeparateShaderTest::iterate (void)
1392 MovePtr<Pipeline> pipeline;
1394 DE_ASSERT(m_iterations > 0);
1396 if (m_currentIteration == 0)
1397 logParams(log(), m_params);
1399 ++m_currentIteration;
1403 (this->*m_testFunc)(pipeline);
1404 log().writeMessage("");
1406 catch (const tcu::Exception&)
1409 logPipeline(log(), *pipeline);
1413 if (m_status.getResult() != QP_TEST_RESULT_PASS)
1416 logPipeline(log(), *pipeline);
1418 else if (m_currentIteration < m_iterations)
1421 m_status.setTestContextResult(m_testCtx);
1425 // Group construction utilities
1429 PARAMFLAGS_SWITCH_FRAGMENT = 1 << 0,
1430 PARAMFLAGS_SWITCH_VERTEX = 1 << 1,
1431 PARAMFLAGS_INIT_SINGLE = 1 << 2,
1432 PARAMFLAGS_LAST = 1 << 3,
1433 PARAMFLAGS_MASK = PARAMFLAGS_LAST - 1
1436 bool areCaseParamFlagsValid (ParamFlags flags)
1438 const ParamFlags switchAll = ParamFlags(PARAMFLAGS_SWITCH_VERTEX|PARAMFLAGS_SWITCH_FRAGMENT);
1440 if ((flags & PARAMFLAGS_INIT_SINGLE) != 0)
1441 return (flags & switchAll) == 0 ||
1442 (flags & switchAll) == switchAll;
1447 bool addRenderTest (TestCaseGroup& group, const string& namePrefix, const string& descPrefix,
1448 int numIterations, ParamFlags flags, TestParams params)
1453 DE_ASSERT(areCaseParamFlagsValid(flags));
1458 params.initSingle = (flags & PARAMFLAGS_INIT_SINGLE) != 0;
1459 params.switchVtx = (flags & PARAMFLAGS_SWITCH_VERTEX) != 0;
1460 params.switchFrg = (flags & PARAMFLAGS_SWITCH_FRAGMENT) != 0;
1462 name << (flags & PARAMFLAGS_INIT_SINGLE ? "single_program" : "separate_programs");
1463 desc << (flags & PARAMFLAGS_INIT_SINGLE
1464 ? "Single program with two shaders"
1465 : "Separate programs for each shader");
1467 switch (flags & (PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX))
1471 case PARAMFLAGS_SWITCH_FRAGMENT:
1472 name << "_add_fragment";
1473 desc << ", then add a fragment program";
1475 case PARAMFLAGS_SWITCH_VERTEX:
1476 name << "_add_vertex";
1477 desc << ", then add a vertex program";
1479 case PARAMFLAGS_SWITCH_FRAGMENT | PARAMFLAGS_SWITCH_VERTEX:
1480 name << "_add_both";
1481 desc << ", then add both vertex and shader programs";
1485 if (!paramsValid(params))
1488 group.addChild(new SeparateShaderTest(group.getContext(), name.str(), desc.str(),
1489 numIterations, params,
1490 &SeparateShaderTest::testPipelineRendering));
1495 void describeInterpolation(const string& stage, Interpolation qual,
1496 ostringstream& name, ostringstream& desc)
1498 if (qual == glu::INTERPOLATION_LAST)
1500 desc << ", unqualified in " << stage << " shader";
1505 const string qualName = glu::getInterpolationName(qual);
1507 name << "_" << stage << "_" << qualName;
1508 desc << ", qualified '" << qualName << "' in " << stage << " shader";
1513 } // anonymous namespace
1515 TestCaseGroup* createSeparateShaderTests (Context& ctx)
1517 TestParams defaultParams;
1518 int numIterations = 4;
1519 TestCaseGroup* group =
1520 new TestCaseGroup(ctx, "separate_shader", "Separate shader tests");
1522 defaultParams.useUniform = false;
1523 defaultParams.initSingle = false;
1524 defaultParams.switchVtx = false;
1525 defaultParams.switchFrg = false;
1526 defaultParams.useCreateHelper = false;
1527 defaultParams.useProgramUniform = false;
1528 defaultParams.useSameName = false;
1529 defaultParams.varyings.count = 0;
1530 defaultParams.varyings.type = glu::TYPE_INVALID;
1531 defaultParams.varyings.binding = BINDING_NAME;
1532 defaultParams.varyings.vtxInterp = glu::INTERPOLATION_LAST;
1533 defaultParams.varyings.frgInterp = glu::INTERPOLATION_LAST;
1535 TestCaseGroup* stagesGroup =
1536 new TestCaseGroup(ctx, "pipeline", "Pipeline configuration tests");
1537 group->addChild(stagesGroup);
1539 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST << 2; ++flags)
1541 TestParams params = defaultParams;
1545 if (!areCaseParamFlagsValid(ParamFlags(flags & PARAMFLAGS_MASK)))
1548 if (flags & (PARAMFLAGS_LAST << 1))
1550 params.useSameName = true;
1552 desc << "Identically named ";
1556 name << "different_";
1557 desc << "Differently named ";
1560 if (flags & PARAMFLAGS_LAST)
1562 params.useUniform = true;
1564 desc << "uniforms, ";
1568 name << "constant_";
1569 desc << "constants, ";
1572 addRenderTest(*stagesGroup, name.str(), desc.str(), numIterations,
1573 ParamFlags(flags & PARAMFLAGS_MASK), params);
1576 TestCaseGroup* programUniformGroup =
1577 new TestCaseGroup(ctx, "program_uniform", "ProgramUniform tests");
1578 group->addChild(programUniformGroup);
1580 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1582 TestParams params = defaultParams;
1584 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1587 params.useUniform = true;
1588 params.useProgramUniform = true;
1590 addRenderTest(*programUniformGroup, "", "", numIterations, ParamFlags(flags), params);
1593 TestCaseGroup* createShaderProgramGroup =
1594 new TestCaseGroup(ctx, "create_shader_program", "CreateShaderProgram tests");
1595 group->addChild(createShaderProgramGroup);
1597 for (deUint32 flags = 0; flags < PARAMFLAGS_LAST; ++flags)
1599 TestParams params = defaultParams;
1601 if (!areCaseParamFlagsValid(ParamFlags(flags)))
1604 params.useCreateHelper = true;
1606 addRenderTest(*createShaderProgramGroup, "", "", numIterations,
1607 ParamFlags(flags), params);
1610 TestCaseGroup* interfaceGroup =
1611 new TestCaseGroup(ctx, "interface", "Shader interface compatibility tests");
1612 group->addChild(interfaceGroup);
1616 NUM_INTERPOLATIONS = glu::INTERPOLATION_LAST + 1, // INTERPOLATION_LAST is valid
1617 INTERFACEFLAGS_LAST = BINDING_LAST * NUM_INTERPOLATIONS * NUM_INTERPOLATIONS
1620 for (deUint32 flags = 0; flags < INTERFACEFLAGS_LAST; ++flags)
1622 deUint32 tmpFlags = flags;
1623 Interpolation frgInterp = Interpolation(tmpFlags % NUM_INTERPOLATIONS);
1624 Interpolation vtxInterp = Interpolation((tmpFlags /= NUM_INTERPOLATIONS)
1625 % NUM_INTERPOLATIONS);
1626 BindingKind binding = BindingKind((tmpFlags /= NUM_INTERPOLATIONS)
1628 TestParams params = defaultParams;
1632 params.varyings.count = 1;
1633 params.varyings.type = glu::TYPE_FLOAT;
1634 params.varyings.binding = binding;
1635 params.varyings.vtxInterp = vtxInterp;
1636 params.varyings.frgInterp = frgInterp;
1640 case BINDING_LOCATION:
1641 name << "same_location";
1642 desc << "Varyings have same location, ";
1645 name << "same_name";
1646 desc << "Varyings have same name, ";
1649 DE_ASSERT(!"Impossible");
1652 describeInterpolation("vertex", vtxInterp, name, desc);
1653 describeInterpolation("fragment", frgInterp, name, desc);
1655 if (!paramsValid(params))
1658 interfaceGroup->addChild(
1659 new SeparateShaderTest(ctx, name.str(), desc.str(), numIterations, params,
1660 &SeparateShaderTest::testPipelineRendering));
1663 deUint32 baseSeed = ctx.getTestContext().getCommandLine().getBaseSeed();
1664 Random rnd (deStringHash("separate_shader.random") + baseSeed);
1666 TestCaseGroup* randomGroup = new TestCaseGroup(
1667 ctx, "random", "Random pipeline configuration tests");
1668 group->addChild(randomGroup);
1670 for (deUint32 i = 0; i < 128; ++i)
1674 deUint32 genIterations = 4096;
1678 params = genParams(rnd.getUint32());
1679 code = paramsCode(params);
1680 } while (de::contains(seen, code) && --genIterations > 0);
1684 string name = de::toString(i); // Would be code but baseSeed can change
1686 randomGroup->addChild(new SeparateShaderTest(
1687 ctx, name, name, numIterations, params,
1688 &SeparateShaderTest::testPipelineRendering));
1691 TestCaseGroup* apiGroup =
1692 new TestCaseGroup(ctx, "api", "Program pipeline API tests");
1693 group->addChild(apiGroup);
1696 // More or less random parameters. These shouldn't have much effect, so just
1697 // do a single sample.
1698 TestParams params = defaultParams;
1699 params.useUniform = true;
1700 apiGroup->addChild(new SeparateShaderTest(
1702 "current_program_priority",
1703 "Test priority between current program and pipeline binding",
1704 1, params, &SeparateShaderTest::testCurrentProgPriority));
1705 apiGroup->addChild(new SeparateShaderTest(
1707 "active_program_uniform",
1708 "Test that glUniform() affects a pipeline's active program",
1709 1, params, &SeparateShaderTest::testActiveProgramUniform));
1711 apiGroup->addChild(new SeparateShaderTest(
1713 "pipeline_programs",
1714 "Test queries for programs in program pipeline stages",
1715 1, params, &SeparateShaderTest::testPipelineQueryPrograms));
1717 apiGroup->addChild(new SeparateShaderTest(
1720 "Test query for active programs in a program pipeline",
1721 1, params, &SeparateShaderTest::testPipelineQueryActive));
1724 TestCaseGroup* interfaceMismatchGroup =
1725 new TestCaseGroup(ctx, "validation", "Negative program pipeline interface matching");
1726 group->addChild(interfaceMismatchGroup);
1729 gls::ShaderLibrary shaderLibrary (ctx.getTestContext(), ctx.getRenderContext(), ctx.getContextInfo());
1730 const std::vector<tcu::TestNode*> children = shaderLibrary.loadShaderFile("shaders/separate_shader_validation.test");
1732 for (int i = 0; i < (int)children.size(); i++)
1733 interfaceMismatchGroup->addChild(children[i]);