/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.0 Module * ------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Long running shader stress tests. *//*--------------------------------------------------------------------*/ #include "es3sLongRunningShaderTests.hpp" #include "gluShaderProgram.hpp" #include "gluShaderUtil.hpp" #include "gluDrawUtil.hpp" #include "tcuRenderTarget.hpp" #include "tcuVector.hpp" #include "tcuTestLog.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "deString.h" #include "glwFunctions.hpp" #include "glwEnums.hpp" namespace deqp { namespace gles3 { namespace Stress { using tcu::TestLog; using tcu::Vec2; using std::vector; namespace { enum LoopType { LOOPTYPE_FOR = 0, LOOPTYPE_WHILE, LOOPTYPE_DO_WHILE, LOOPTYPE_LAST }; enum IterCountType { ITERCOUNTTYPE_STATIC = 0, ITERCOUNTTYPE_UNIFORM, ITERCOUNTTYPE_DYNAMIC, ITERCOUNTTYPE_LAST }; class LongRunningShaderCase : public TestCase { public: struct Params { const char* name; const char* description; glu::ShaderType shaderType; LoopType loopType; IterCountType iterCountType; int numInvocations; int minLoopIterCount; int maxLoopIterCount; }; LongRunningShaderCase (Context& context, const Params* params); ~LongRunningShaderCase (void); void init (void); void deinit (void); IterateResult iterate (void); private: LongRunningShaderCase (const LongRunningShaderCase&); LongRunningShaderCase& operator= (const LongRunningShaderCase&); static glu::ProgramSources genSources (const Params& params); static deUint32 getSeed (const Params& params); const Params* const m_params; const int m_numCaseIters; glu::ShaderProgram* m_program; int m_caseIterNdx; }; LongRunningShaderCase::LongRunningShaderCase (Context& context, const Params* params) : TestCase (context, params->name, params->description) , m_params (params) , m_numCaseIters (5) , m_program (DE_NULL) , m_caseIterNdx (0) { } LongRunningShaderCase::~LongRunningShaderCase (void) { deinit(); } glu::ProgramSources LongRunningShaderCase::genSources (const Params& params) { const bool isVertCase = params.shaderType == glu::SHADERTYPE_VERTEX; std::ostringstream vert, frag; vert << "#version 300 es\n" << "in highp vec2 a_position;\n"; frag << "#version 300 es\n"; if (params.iterCountType == ITERCOUNTTYPE_DYNAMIC) { vert << "in highp int a_iterCount;\n"; if (!isVertCase) { vert << "flat out highp int v_iterCount;\n"; frag << "flat in highp int v_iterCount;\n"; } } else if (params.iterCountType == ITERCOUNTTYPE_UNIFORM) (isVertCase ? vert : frag) << "uniform highp int u_iterCount;\n"; if (isVertCase) { vert << "out mediump vec4 v_color;\n"; frag << "in mediump vec4 v_color;\n"; } frag << "out mediump vec4 o_color;\n"; vert << "\nvoid main (void)\n{\n" << " gl_Position = vec4(a_position, 0.0, 1.0);\n" << " gl_PointSize = 1.0;\n"; if (!isVertCase && params.iterCountType == ITERCOUNTTYPE_DYNAMIC) vert << " v_iterCount = a_iterCount;\n"; frag << "\nvoid main (void)\n{\n"; { const std::string iterCount = params.iterCountType == ITERCOUNTTYPE_DYNAMIC ? (isVertCase ? "a_iterCount" : "v_iterCount") : params.iterCountType == ITERCOUNTTYPE_UNIFORM ? "u_iterCount" : params.iterCountType == ITERCOUNTTYPE_STATIC ? de::toString(params.maxLoopIterCount) : "<invalid>"; const char* const body = "color = cos(sin(color*1.25)*0.8);"; std::ostringstream& op = isVertCase ? vert : frag; op << " mediump vec4 color = " << (isVertCase ? "a_position.xyxy" : "gl_FragCoord") << ";\n"; if (params.loopType == LOOPTYPE_FOR) { op << " for (highp int i = 0; i < " << iterCount << " || " << iterCount << " < 0; ++i)\n" << " " << body << "\n"; } else if (params.loopType == LOOPTYPE_WHILE) { op << " highp int i = 0;\n" << " while (i < " << iterCount << " || " << iterCount << " < 0) {\n" << " i += 1;\n" << " " << body << "\n" << " }\n"; } else { DE_ASSERT(params.loopType == LOOPTYPE_DO_WHILE); op << " highp int i = 0;\n" << " do {\n" << " i += 1;\n" << " " << body << "\n" << " } while (i <= " << iterCount << " || " << iterCount << " < 0);\n"; } } if (isVertCase) { vert << " v_color = color;\n"; frag << " o_color = v_color;\n"; } else frag << " o_color = color;\n"; vert << "}\n"; frag << "}\n"; return glu::ProgramSources() << glu::VertexSource(vert.str()) << glu::FragmentSource(frag.str()); } void LongRunningShaderCase::init (void) { DE_ASSERT(!m_program); m_program = new glu::ShaderProgram(m_context.getRenderContext(), genSources(*m_params)); m_testCtx.getLog() << *m_program; if (!m_program->isOk()) { deinit(); TCU_FAIL("Failed to compile shader program"); } m_caseIterNdx = 0; if (m_params->iterCountType != ITERCOUNTTYPE_STATIC) { m_testCtx.getLog() << TestLog::Message << "Loop iteration counts in range: [" << m_params->minLoopIterCount << ", " << m_params->maxLoopIterCount << "]" << TestLog::EndMessage; } m_testCtx.getLog() << TestLog::Message << "Number of vertices and fragments: " << m_params->numInvocations << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Test will pass or timeout, unless driver/device crashes. } void LongRunningShaderCase::deinit (void) { delete m_program; m_program = DE_NULL; } void genPositions (const tcu::RenderTarget& renderTarget, int numPoints, Vec2* positions) { const int width = renderTarget.getWidth(); const int height = renderTarget.getHeight(); if (width*height < numPoints) throw tcu::NotSupportedError("Too small viewport to fit all test points"); for (int pointNdx = 0; pointNdx < numPoints; pointNdx++) { const int xi = pointNdx % width; const int yi = pointNdx / height; const float xf = 2.0f * ((float(xi) + 0.5f) / float(width)) - 1.0f; const float yf = 2.0f * ((float(yi) + 0.5f) / float(height)) - 1.0f; positions[pointNdx] = Vec2(xf, yf); } } deUint32 LongRunningShaderCase::getSeed (const Params& params) { const deUint32 seed = deStringHash(params.name) ^ deInt32Hash(params.shaderType) ^ deInt32Hash(params.loopType) ^ deInt32Hash(params.iterCountType) ^ deInt32Hash(params.minLoopIterCount) ^ deInt32Hash(params.maxLoopIterCount) ^ deInt32Hash(params.numInvocations); return seed; } LongRunningShaderCase::IterateResult LongRunningShaderCase::iterate (void) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); de::Random rnd (getSeed(*m_params)); vector<Vec2> positions (m_params->numInvocations); vector<int> iterCounts (m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC ? m_params->numInvocations : 1); vector<glu::VertexArrayBinding> vertexArrays; vertexArrays.push_back(glu::va::Float("a_position", 2, (int)positions.size(), 0, positions[0].getPtr())); if (m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC) vertexArrays.push_back(glu::va::Int32("a_iterCount", 1, (int)iterCounts.size(), 0, &iterCounts[0])); genPositions(m_context.getRenderTarget(), (int)positions.size(), &positions[0]); for (vector<int>::iterator i = iterCounts.begin(); i != iterCounts.end(); ++i) *i = rnd.getInt(m_params->minLoopIterCount, m_params->maxLoopIterCount); gl.useProgram(m_program->getProgram()); if (m_params->iterCountType == ITERCOUNTTYPE_UNIFORM) gl.uniform1i(gl.getUniformLocation(m_program->getProgram(), "u_iterCount"), iterCounts[0]); glu::draw(m_context.getRenderContext(), m_program->getProgram(), (int)vertexArrays.size(), &vertexArrays[0], glu::pr::Points(m_params->numInvocations)); m_caseIterNdx += 1; return (m_caseIterNdx < m_numCaseIters) ? CONTINUE : STOP; } } // anonymous LongRunningShaderTests::LongRunningShaderTests (Context& context) : TestCaseGroup(context, "long_running_shaders", "Long-running shader stress tests") { } LongRunningShaderTests::~LongRunningShaderTests (void) { } void LongRunningShaderTests::init (void) { const int numInvocations = 4096; const int shortLoopMin = 5; const int shortLoopMax = 10; const int mediumLoopMin = 10000; const int mediumLoopMax = 50000; const int longLoopMin = 100000; const int longLoopMax = 500000; static const LongRunningShaderCase::Params s_cases[] = { { "short_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "short_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "short_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "short_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "short_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "short_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, shortLoopMin, shortLoopMax }, { "medium_static_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_STATIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_static_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_STATIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_uniform_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_UNIFORM, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_uniform_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_UNIFORM, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "medium_dynamic_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, mediumLoopMin, mediumLoopMax }, { "long_static_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_STATIC, numInvocations, longLoopMin, longLoopMax }, { "long_static_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_STATIC, numInvocations, longLoopMin, longLoopMax }, { "long_uniform_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_UNIFORM, numInvocations, longLoopMin, longLoopMax }, { "long_uniform_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_UNIFORM, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "long_dynamic_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, longLoopMin, longLoopMax }, { "infinite_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, { "infinite_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, { "infinite_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, { "infinite_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, { "infinite_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, { "infinite_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1, -1 }, }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_cases); ndx++) addChild(new LongRunningShaderCase(m_context, &s_cases[ndx])); } } // Stress } // gles3 } // deqp