| /*------------------------------------------------------------------------- |
| * 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 |