/*------------------------------------------------------------------------- * 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 Occlusion query stress tests *//*--------------------------------------------------------------------*/ #include "es3sOcclusionQueryTests.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "deString.h" #include "tcuTestLog.hpp" #include "tcuVector.hpp" #include "tcuSurface.hpp" #include "gluShaderProgram.hpp" #include "deClock.h" #include "glw.h" #include <vector> using std::vector; using tcu::TestLog; namespace deqp { namespace gles3 { namespace Stress { static const tcu::Vec4 OCCLUDER_COLOR = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f); static const tcu::Vec4 TARGET_COLOR = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f); static const int NUM_CASE_ITERATIONS = 3; static const int NUM_GENERATED_VERTICES = 100; static const int WATCHDOG_INTERVAL = 50; // Touch watchdog every N iterations. class OcclusionQueryStressCase : public TestCase { public: OcclusionQueryStressCase (Context& ctx, const char* name, const char* desc, int m_numOccluderDraws, int m_numOccludersPerDraw, int m_numTargetDraws, int m_numTargetsPerDraw, int m_numQueries, deUint32 m_queryMode); ~OcclusionQueryStressCase (void); void init (void); void deinit (void); IterateResult iterate (void); private: OcclusionQueryStressCase (const OcclusionQueryStressCase&); OcclusionQueryStressCase& operator= (const OcclusionQueryStressCase&); int m_numOccluderDraws; int m_numOccludersPerDraw; int m_numTargetDraws; int m_numTargetsPerDraw; int m_numQueries; deUint32 m_queryMode; glu::RenderContext& m_renderCtx; glu::ShaderProgram* m_program; int m_iterNdx; de::Random m_rnd; }; OcclusionQueryStressCase::OcclusionQueryStressCase (Context& ctx, const char* name, const char* desc, int numOccluderDraws, int numOccludersPerDraw, int numTargetDraws, int numTargetsPerDraw, int numQueries, deUint32 queryMode) : TestCase (ctx, name, desc) , m_numOccluderDraws (numOccluderDraws) , m_numOccludersPerDraw (numOccludersPerDraw) , m_numTargetDraws (numTargetDraws) , m_numTargetsPerDraw (numTargetsPerDraw) , m_numQueries (numQueries) , m_queryMode (queryMode) , m_renderCtx (ctx.getRenderContext()) , m_program (DE_NULL) , m_iterNdx (0) , m_rnd (deStringHash(name)) { } OcclusionQueryStressCase::~OcclusionQueryStressCase (void) { OcclusionQueryStressCase::deinit(); } void OcclusionQueryStressCase::init (void) { const char* vertShaderSource = "#version 300 es\n" "layout(location = 0) in mediump vec4 a_position;\n" "\n" "void main (void)\n" "{\n" " gl_Position = a_position;\n" "}\n"; const char* fragShaderSource = "#version 300 es\n" "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" "uniform mediump vec4 u_color;\n" "\n" "void main (void)\n" "{\n" " mediump float depth_gradient = gl_FragCoord.z;\n" " mediump float bias = 0.1;\n" " dEQP_FragColor = vec4(u_color.xyz * (depth_gradient + bias), 1.0);\n" "}\n"; DE_ASSERT(!m_program); m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource)); if (!m_program->isOk()) { m_testCtx.getLog() << *m_program; TCU_FAIL("Failed to compile shader program"); } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Initialize test result to pass. GLU_CHECK_MSG ("Case initialization finished"); } void OcclusionQueryStressCase::deinit (void) { delete m_program; m_program = DE_NULL; } OcclusionQueryStressCase::IterateResult OcclusionQueryStressCase::iterate (void) { tcu::TestLog& log = m_testCtx.getLog(); deUint32 colorUnif = glGetUniformLocation(m_program->getProgram(), "u_color"); std::vector<float> vertices; std::vector<float> occluderVertices; std::vector<float> targetVertices; std::vector<deUint32> queryIds (m_numQueries, 0); std::vector<deUint32> queryResultReady (m_numQueries, 0); std::vector<deUint32> queryResult (m_numQueries, 0); std::string sectionName ("Case iteration " + de::toString(m_iterNdx+1) + "/" + de::toString(NUM_CASE_ITERATIONS)); tcu::ScopedLogSection section (log, sectionName.c_str(), sectionName.c_str()); log << tcu::TestLog::Message << "Parameters:\n" << "- Number of occlusion queries: " << m_numQueries << ".\n" << "- Number of occluder draws per query: " << m_numOccluderDraws << ", primitives per draw: " << m_numOccludersPerDraw << ".\n" << "- Number of target draws per query: " << m_numTargetDraws << ", primitives per draw: " << m_numTargetsPerDraw << ".\n" << tcu::TestLog::EndMessage; int numOccluderIndicesPerDraw = 3*m_numOccludersPerDraw; int numTargetIndicesPerDraw = 3*m_numTargetsPerDraw; // Generate vertex data vertices.resize(4*NUM_GENERATED_VERTICES); for (int i = 0; i < NUM_GENERATED_VERTICES; i++) { vertices[4*i ] = m_rnd.getFloat(-1.0f, 1.0f); vertices[4*i + 1] = m_rnd.getFloat(-1.0f, 1.0f); vertices[4*i + 2] = m_rnd.getFloat(0.0f, 1.0f); vertices[4*i + 3] = 1.0f; } // Generate primitives occluderVertices.resize(4*numOccluderIndicesPerDraw * m_numOccluderDraws); for (int i = 0; i < numOccluderIndicesPerDraw * m_numOccluderDraws; i++) { int vtxNdx = m_rnd.getInt(0, NUM_GENERATED_VERTICES-1); occluderVertices[4*i ] = vertices[4*vtxNdx]; occluderVertices[4*i + 1] = vertices[4*vtxNdx + 1]; occluderVertices[4*i + 2] = vertices[4*vtxNdx + 2]; occluderVertices[4*i + 3] = vertices[4*vtxNdx + 3]; } targetVertices.resize(4*numTargetIndicesPerDraw * m_numTargetDraws); for (int i = 0; i < numTargetIndicesPerDraw * m_numTargetDraws; i++) { int vtxNdx = m_rnd.getInt(0, NUM_GENERATED_VERTICES-1); targetVertices[4*i ] = vertices[4*vtxNdx]; targetVertices[4*i + 1] = vertices[4*vtxNdx + 1]; targetVertices[4*i + 2] = vertices[4*vtxNdx + 2]; targetVertices[4*i + 3] = vertices[4*vtxNdx + 3]; } TCU_CHECK(m_program); glClearColor (0.0f, 0.0f, 0.0f, 1.0f); glClearDepthf (1.0f); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable (GL_DEPTH_TEST); glUseProgram (m_program->getProgram()); glEnableVertexAttribArray (0); deUint64 time = deGetMicroseconds(); for (int queryIter = 0; queryIter < m_numQueries; queryIter++) { // Draw occluders glUniform4f (colorUnif, OCCLUDER_COLOR.x(), OCCLUDER_COLOR.y(), OCCLUDER_COLOR.z(), OCCLUDER_COLOR.w()); for (int drawIter = 0; drawIter < m_numOccluderDraws; drawIter++) { glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, &occluderVertices[drawIter * numOccluderIndicesPerDraw]); glDrawArrays (GL_TRIANGLES, 0, numOccluderIndicesPerDraw); } // Begin occlusion query glGenQueries (1, &queryIds[queryIter]); glBeginQuery (m_queryMode, queryIds[queryIter]); // Draw targets glUniform4f (colorUnif, TARGET_COLOR.x(), TARGET_COLOR.y(), TARGET_COLOR.z(), TARGET_COLOR.w()); for (int drawIter = 0; drawIter < m_numTargetDraws; drawIter++) { glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, &targetVertices[drawIter * numTargetIndicesPerDraw]); glDrawArrays (GL_TRIANGLES, 0, numTargetIndicesPerDraw); } // End occlusion query glEndQuery (m_queryMode); if ((queryIter % WATCHDOG_INTERVAL) == 0 && m_testCtx.getWatchDog()) qpWatchDog_touch(m_testCtx.getWatchDog()); } glFinish(); glDisable(GL_DEPTH_TEST); deUint64 dTime = deGetMicroseconds() - time; log << tcu::TestLog::Message << "Total duration: " << dTime/1000 << " ms" << tcu::TestLog::EndMessage; // Get results for (int queryIter = 0; queryIter < m_numQueries; queryIter++) { glGetQueryObjectuiv(queryIds[queryIter], GL_QUERY_RESULT_AVAILABLE, &queryResultReady[queryIter]); if (queryResultReady[queryIter] == GL_TRUE) { glGetQueryObjectuiv(queryIds[queryIter], GL_QUERY_RESULT, &queryResult[queryIter]); } else TCU_FAIL("Occlusion query failed to return a result after glFinish()"); if ((queryIter % WATCHDOG_INTERVAL) == 0 && m_testCtx.getWatchDog()) qpWatchDog_touch(m_testCtx.getWatchDog()); } glDeleteQueries (m_numQueries, &queryIds[0]); GLU_CHECK_MSG ("Occlusion queries finished"); log << tcu::TestLog::Message << "Case passed!" << tcu::TestLog::EndMessage; return (++m_iterNdx < NUM_CASE_ITERATIONS) ? CONTINUE : STOP; } OcclusionQueryTests::OcclusionQueryTests (Context& testCtx) : TestCaseGroup(testCtx, "occlusion_query", "Occlusion query stress tests") { } OcclusionQueryTests::~OcclusionQueryTests(void) { } void OcclusionQueryTests::init (void) { addChild(new OcclusionQueryStressCase(m_context, "10_queries_2500_triangles_per_query", "10_queries_2500_triangles_per_query", 49, 50, 1, 50, 10, GL_ANY_SAMPLES_PASSED)); addChild(new OcclusionQueryStressCase(m_context, "100_queries_2500_triangles_per_query", "100_queries_2500_triangles_per_query", 49, 50, 1, 50, 100, GL_ANY_SAMPLES_PASSED)); addChild(new OcclusionQueryStressCase(m_context, "1000_queries_500_triangles_per_query", "1000_queries_500_triangles_per_query", 49, 10, 1, 10, 1000, GL_ANY_SAMPLES_PASSED)); addChild(new OcclusionQueryStressCase(m_context, "10000_queries_20_triangles_per_query", "10000_queries_20_triangles_per_query", 1, 19, 1, 1, 10000, GL_ANY_SAMPLES_PASSED)); } } // Stress } // gles3 } // deqp