| /*------------------------------------------------------------------------- |
| * 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 stress tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3sLongRunningTests.hpp" |
| #include "glsLongStressCase.hpp" |
| #include "glsLongStressTestUtil.hpp" |
| #include "glwEnums.hpp" |
| |
| #include <string> |
| |
| using std::string; |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Stress |
| { |
| |
| LongRunningTests::LongRunningTests (Context& context) |
| : TestCaseGroup(context, "long", "Long-running stress tests") |
| { |
| } |
| |
| LongRunningTests::~LongRunningTests (void) |
| { |
| } |
| |
| void LongRunningTests::init (void) |
| { |
| static const int Mi = 1<<20; |
| const gls::LongStressTestUtil::ProgramLibrary progLib (glu::GLSL_VERSION_300_ES); |
| |
| typedef gls::LongStressCase::FeatureProbabilities Probs; |
| |
| // Buffer cases. |
| |
| { |
| static const struct MemCase |
| { |
| const char* const nameSuffix; |
| const char* const descSuffix; |
| const int limit; |
| const int redundantBufferFactor; |
| MemCase (const char* n, const char* d, int l, int r) : nameSuffix(n), descSuffix(d), limit(l), redundantBufferFactor(r) {} |
| } memoryLimitCases[] = |
| { |
| MemCase("_low_memory", "; use a low buffer memory usage limit", 8*Mi, 2), |
| MemCase("_high_memory", "; use a high buffer memory usage limit", 256*Mi, 64) |
| }; |
| |
| const std::vector<gls::ProgramContext> contexts(1, progLib.generateBufferContext(4)); |
| |
| static const struct Case |
| { |
| const char* const name; |
| const char* const desc; |
| const int redundantBufferFactor; //!< If non-positive, taken from memoryLimitCases. |
| const Probs probs; |
| Case (const char* const name_, const char* const desc_, int bufFact, const Probs& probs_ = Probs()) : name(name_), desc(desc_), redundantBufferFactor(bufFact), probs(probs_) {} |
| } cases[] = |
| { |
| Case("always_reupload", |
| "Re-upload buffer data at the beginning of each iteration", |
| -1, |
| Probs().pReuploadBuffer(1.0f)), |
| |
| Case("always_reupload_bufferdata", |
| "Re-upload buffer data at the beginning of each iteration, using glBufferData", |
| -1, |
| Probs().pReuploadBuffer(1.0f).pReuploadWithBufferData(1.0f)), |
| |
| Case("always_delete", |
| "Delete buffers at the end of each iteration, and re-create at the beginning of the next", |
| -1, |
| Probs().pDeleteBuffer(1.0f)), |
| |
| Case("wasteful", |
| "Don't reuse buffers, and only delete them when given memory limit is reached", |
| 2, |
| Probs().pWastefulBufferMemoryUsage(1.0f)), |
| |
| Case("separate_attribute_buffers_wasteful", |
| "Give each vertex attribute its own buffer", |
| 2, |
| Probs().pSeparateAttribBuffers(1.0f).pWastefulBufferMemoryUsage(1.0f)) |
| }; |
| |
| TestCaseGroup* const bufferGroup = new TestCaseGroup(m_context, "buffer", "Buffer stress tests"); |
| addChild(bufferGroup); |
| |
| for (int memoryLimitNdx = 0; memoryLimitNdx < DE_LENGTH_OF_ARRAY(memoryLimitCases); memoryLimitNdx++) |
| { |
| for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) |
| { |
| const int redundantBufferFactor = cases[caseNdx].redundantBufferFactor > 0 ? cases[caseNdx].redundantBufferFactor : memoryLimitCases[memoryLimitNdx].redundantBufferFactor; |
| |
| bufferGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| (string() + cases[caseNdx].name + memoryLimitCases[memoryLimitNdx].nameSuffix).c_str(), |
| (string() + cases[caseNdx].desc + memoryLimitCases[memoryLimitNdx].descSuffix).c_str(), |
| 0 /* tex memory */, memoryLimitCases[memoryLimitNdx].limit, |
| 1 /* draw calls per iteration */, 50000 /* tris per call */, |
| contexts, cases[caseNdx].probs, |
| GL_DYNAMIC_DRAW, GL_DYNAMIC_DRAW, |
| redundantBufferFactor)); |
| } |
| } |
| } |
| |
| // Texture cases. |
| |
| { |
| static const struct MemCase |
| { |
| const char* const nameSuffix; |
| const char* const descSuffix; |
| const int limit; |
| const int numTextures; |
| MemCase (const char* n, const char* d, int l, int t) : nameSuffix(n), descSuffix(d), limit(l), numTextures(t) {} |
| } memoryLimitCases[] = |
| { |
| MemCase("_low_memory", "; use a low texture memory usage limit", 8*Mi, 6), |
| MemCase("_high_memory", "; use a high texture memory usage limit", 256*Mi, 192) |
| }; |
| |
| static const struct Case |
| { |
| const char* const name; |
| const char* const desc; |
| const int numTextures; //!< If non-positive, taken from memoryLimitCases. |
| const Probs probs; |
| Case (const char* const name_, const char* const desc_, int numTextures_, const Probs& probs_ = Probs()) : name(name_), desc(desc_), numTextures(numTextures_), probs(probs_) {} |
| } cases[] = |
| { |
| Case("always_reupload", |
| "Re-upload texture data at the beginning of each iteration", |
| -1, |
| Probs().pReuploadTexture(1.0f)), |
| |
| Case("always_reupload_teximage", |
| "Re-upload texture data at the beginning of each iteration, using glTexImage*", |
| -1, |
| Probs().pReuploadTexture(1.0f).pReuploadWithTexImage(1.0f)), |
| |
| Case("always_delete", |
| "Delete textures at the end of each iteration, and re-create at the beginning of the next", |
| -1, |
| Probs().pDeleteTexture(1.0f)), |
| |
| Case("wasteful", |
| "Don't reuse textures, and only delete them when given memory limit is reached", |
| 6, |
| Probs().pWastefulTextureMemoryUsage(1.0f)) |
| }; |
| |
| TestCaseGroup* const textureGroup = new TestCaseGroup(m_context, "texture", "Texture stress tests"); |
| addChild(textureGroup); |
| |
| for (int memoryLimitNdx = 0; memoryLimitNdx < DE_LENGTH_OF_ARRAY(memoryLimitCases); memoryLimitNdx++) |
| { |
| for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) |
| { |
| const int numTextures = cases[caseNdx].numTextures > 0 ? cases[caseNdx].numTextures : memoryLimitCases[memoryLimitNdx].numTextures; |
| const std::vector<gls::ProgramContext> contexts (1, progLib.generateTextureContext(numTextures, 512, 512, 0.1f)); |
| |
| textureGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| (string() + cases[caseNdx].name + memoryLimitCases[memoryLimitNdx].nameSuffix).c_str(), |
| (string() + cases[caseNdx].desc + memoryLimitCases[memoryLimitNdx].descSuffix).c_str(), |
| memoryLimitCases[memoryLimitNdx].limit, 1*Mi /* buf memory */, |
| 1 /* draw calls per iteration */, 10000 /* tris per call */, |
| contexts, cases[caseNdx].probs, |
| GL_STATIC_DRAW, GL_STATIC_DRAW)); |
| } |
| } |
| } |
| |
| // Draw call cases. |
| |
| { |
| const std::vector<gls::ProgramContext> contexts(1, progLib.generateTextureContext(1, 128, 128, 0.5f)); |
| |
| static const struct Case |
| { |
| const char* const name; |
| const char* const desc; |
| const int drawCallsPerIteration; |
| const int numTrisPerDrawCall; |
| const Probs probs; |
| Case (const char* const name_, const char* const desc_, const int calls, const int tris, const Probs& probs_ = Probs()) |
| : name(name_), desc(desc_), drawCallsPerIteration(calls), numTrisPerDrawCall(tris), probs(probs_) {} |
| } cases[] = |
| { |
| Case("client_memory_data", |
| "Use client-memory for index and attribute data, instead of GL buffers", |
| 200, 500, |
| Probs().pClientMemoryAttributeData(1.0f).pClientMemoryIndexData(1.0f)), |
| |
| Case("vary_draw_function", |
| "Choose between glDrawElements and glDrawArrays each iteration, with uniform probability", |
| 200, 500, |
| Probs().pUseDrawArrays(0.5f)), |
| |
| Case("few_big_calls", |
| "Per iteration, do a few draw calls with a big number of triangles per call", |
| 2, 50000), |
| |
| Case("many_small_calls", |
| "Per iteration, do many draw calls with a small number of triangles per call", |
| 2000, 50) |
| }; |
| |
| TestCaseGroup* const drawCallGroup = new TestCaseGroup(m_context, "draw_call", "Draw call stress tests"); |
| addChild(drawCallGroup); |
| |
| for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) |
| { |
| drawCallGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| cases[caseNdx].name, cases[caseNdx].desc, |
| 1*Mi /* tex memory */, 2*Mi /* buf memory */, |
| cases[caseNdx].drawCallsPerIteration, cases[caseNdx].numTrisPerDrawCall, |
| contexts, cases[caseNdx].probs, |
| GL_STATIC_DRAW, GL_STATIC_DRAW)); |
| } |
| } |
| |
| // Shader cases. |
| |
| { |
| std::vector<gls::ProgramContext> contexts; |
| contexts.push_back(progLib.generateFragmentPointLightContext(512, 512)); |
| contexts.push_back(progLib.generateVertexUniformLoopLightContext(512, 512)); |
| |
| static const struct Case |
| { |
| const char* const name; |
| const char* const desc; |
| const Probs probs; |
| Case (const char* const name_, const char* const desc_, const Probs& probs_ = Probs()) : name(name_), desc(desc_), probs(probs_) {} |
| } cases[] = |
| { |
| Case("several_programs", |
| "Use several different programs, choosing between them uniformly on each iteration"), |
| |
| Case("several_programs_always_rebuild", |
| "Use several different programs, choosing between them uniformly on each iteration, and always rebuild the program", |
| Probs().pRebuildProgram(1.0f)) |
| }; |
| |
| TestCaseGroup* const shaderGroup = new TestCaseGroup(m_context, "program", "Shader program stress tests"); |
| addChild(shaderGroup); |
| |
| for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++) |
| { |
| shaderGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| cases[caseNdx].name, cases[caseNdx].desc, |
| 3*Mi /* tex memory */, 1*Mi /* buf memory */, |
| 1 /* draw calls per iteration */, 10000 /* tris per call */, |
| contexts, cases[caseNdx].probs, |
| GL_STATIC_DRAW, GL_STATIC_DRAW)); |
| } |
| } |
| |
| // Mixed cases. |
| |
| { |
| static const struct MemCase |
| { |
| const char* const nameSuffix; |
| const char* const descSuffix; |
| const int texLimit; |
| const int bufLimit; |
| MemCase (const char* n, const char* d, int t, int b) : nameSuffix(n), descSuffix(d), texLimit(t), bufLimit(b) {} |
| } memoryLimitCases[] = |
| { |
| MemCase("_low_memory", "; use a low memory usage limit", 8*Mi, 8*Mi), |
| MemCase("_high_memory", "; use a high memory usage limit", 128*Mi, 128*Mi) |
| }; |
| |
| TestCaseGroup* const mixedGroup = new TestCaseGroup(m_context, "mixed", "Mixed stress tests"); |
| addChild(mixedGroup); |
| |
| for (int memoryLimitNdx = 0; memoryLimitNdx < DE_LENGTH_OF_ARRAY(memoryLimitCases); memoryLimitNdx++) |
| { |
| mixedGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| (string() + "buffer_texture_wasteful" + memoryLimitCases[memoryLimitNdx].nameSuffix).c_str(), |
| (string() + "Use both buffers and textures wastefully" + memoryLimitCases[memoryLimitNdx].descSuffix).c_str(), |
| memoryLimitCases[memoryLimitNdx].texLimit, memoryLimitCases[memoryLimitNdx].bufLimit, |
| 1 /* draw calls per iteration */, 10000 /* tris per call */, |
| std::vector<gls::ProgramContext>(1, progLib.generateBufferAndTextureContext(4, 512, 512)), |
| Probs() |
| .pReuploadTexture (0.3f) |
| .pReuploadWithTexImage (0.5f) |
| .pReuploadBuffer (0.3f) |
| .pReuploadWithBufferData (0.5f) |
| .pDeleteTexture (0.2f) |
| .pDeleteBuffer (0.2f) |
| .pWastefulTextureMemoryUsage (0.5f) |
| .pWastefulBufferMemoryUsage (0.5f) |
| .pRandomBufferUploadTarget (1.0f) |
| .pRandomBufferUsage (1.0f), |
| GL_STATIC_DRAW, GL_STATIC_DRAW)); |
| |
| { |
| std::vector<gls::ProgramContext> contexts; |
| contexts.push_back(progLib.generateFragmentPointLightContext(512, 512)); |
| contexts.push_back(progLib.generateVertexUniformLoopLightContext(512, 512)); |
| mixedGroup->addChild(new gls::LongStressCase(m_context.getTestContext(), m_context.getRenderContext(), |
| (string() + "random" + memoryLimitCases[memoryLimitNdx].nameSuffix).c_str(), |
| (string() + "Highly random behavior" + memoryLimitCases[memoryLimitNdx].descSuffix).c_str(), |
| memoryLimitCases[memoryLimitNdx].texLimit, memoryLimitCases[memoryLimitNdx].bufLimit, |
| 1 /* draw calls per iteration */, 10000 /* tris per call */, |
| contexts, |
| Probs() |
| .pRebuildProgram (0.3f) |
| .pReuploadTexture (0.3f) |
| .pReuploadWithTexImage (0.3f) |
| .pReuploadBuffer (0.3f) |
| .pReuploadWithBufferData (0.3f) |
| .pDeleteTexture (0.2f) |
| .pDeleteBuffer (0.2f) |
| .pWastefulTextureMemoryUsage (0.3f) |
| .pWastefulBufferMemoryUsage (0.3f) |
| .pClientMemoryAttributeData (0.2f) |
| .pClientMemoryIndexData (0.2f) |
| .pSeparateAttribBuffers (0.4f) |
| .pUseDrawArrays (0.4f) |
| .pRandomBufferUploadTarget (1.0f) |
| .pRandomBufferUsage (1.0f), |
| GL_STATIC_DRAW, GL_STATIC_DRAW)); |
| } |
| } |
| } |
| } |
| |
| } // Stress |
| } // gles3 |
| } // deqp |