730 lines
20 KiB
C++
730 lines
20 KiB
C++
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL (ES) 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 State change performance tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "glsStateChangePerfTestCases.hpp"
|
|
|
|
#include "tcuTestLog.hpp"
|
|
|
|
#include "gluDefs.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
|
|
#include "deStringUtil.hpp"
|
|
|
|
#include "deClock.h"
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
using std::vector;
|
|
using std::string;
|
|
using tcu::TestLog;
|
|
using namespace glw;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gls
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
struct ResultStats
|
|
{
|
|
double median;
|
|
double mean;
|
|
double variance;
|
|
|
|
deUint64 min;
|
|
deUint64 max;
|
|
};
|
|
|
|
ResultStats calculateStats (const vector<deUint64>& values)
|
|
{
|
|
ResultStats result = { 0.0, 0.0, 0.0, 0xFFFFFFFFFFFFFFFFu, 0 };
|
|
|
|
deUint64 sum = 0;
|
|
|
|
for (int i = 0; i < (int)values.size(); i++)
|
|
sum += values[i];
|
|
|
|
result.mean = ((double)sum) / (double)values.size();
|
|
|
|
for (int i = 0; i < (int)values.size(); i++)
|
|
{
|
|
const double val = (double)values[i];
|
|
result.variance += (val - result.mean) * (val - result.mean);
|
|
}
|
|
|
|
result.variance /= (double)values.size();
|
|
|
|
{
|
|
const int n = (int)(values.size()/2);
|
|
|
|
vector<deUint64> sortedValues = values;
|
|
|
|
std::sort(sortedValues.begin(), sortedValues.end());
|
|
|
|
result.median = (double)sortedValues[n];
|
|
}
|
|
|
|
for (int i = 0; i < (int)values.size(); i++)
|
|
{
|
|
result.min = std::min(result.min, values[i]);
|
|
result.max = std::max(result.max, values[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void genIndices (vector<GLushort>& indices, int triangleCount)
|
|
{
|
|
indices.reserve(triangleCount*3);
|
|
|
|
for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
|
|
{
|
|
indices.push_back((GLushort)(triangleNdx*3));
|
|
indices.push_back((GLushort)(triangleNdx*3+1));
|
|
indices.push_back((GLushort)(triangleNdx*3+2));
|
|
}
|
|
}
|
|
|
|
void genCoords (vector<GLfloat>& coords, int triangleCount)
|
|
{
|
|
coords.reserve(triangleCount * 3 * 2);
|
|
|
|
for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
|
|
{
|
|
if ((triangleNdx % 2) == 0)
|
|
{
|
|
// CW
|
|
coords.push_back(-1.0f);
|
|
coords.push_back(-1.0f);
|
|
|
|
coords.push_back( 1.0f);
|
|
coords.push_back(-1.0f);
|
|
|
|
coords.push_back( 1.0f);
|
|
coords.push_back( 1.0f);
|
|
}
|
|
else
|
|
{
|
|
// CCW
|
|
coords.push_back(-1.0f);
|
|
coords.push_back(-1.0f);
|
|
|
|
coords.push_back(-1.0f);
|
|
coords.push_back( 1.0f);
|
|
|
|
coords.push_back( 1.0f);
|
|
coords.push_back( 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void genTextureData (vector<deUint8>& data, int width, int height)
|
|
{
|
|
data.clear();
|
|
data.reserve(width*height*4);
|
|
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
data.push_back((deUint8)((255*x)/width));
|
|
data.push_back((deUint8)((255*y)/width));
|
|
data.push_back((deUint8)((255*x*y)/(width*height)));
|
|
data.push_back(255);
|
|
}
|
|
}
|
|
}
|
|
|
|
double calculateVariance (const vector<deUint64>& values, double avg)
|
|
{
|
|
double sum = 0.0;
|
|
|
|
for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
|
|
{
|
|
double value = (double)values[valueNdx];
|
|
sum += (value - avg) * (value - avg);
|
|
}
|
|
|
|
return sum / (double)values.size();
|
|
}
|
|
|
|
deUint64 findMin (const vector<deUint64>& values)
|
|
{
|
|
deUint64 min = ~0ull;
|
|
|
|
for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
|
|
min = std::min(values[valueNdx], min);
|
|
|
|
return min;
|
|
}
|
|
|
|
deUint64 findMax (const vector<deUint64>& values)
|
|
{
|
|
deUint64 max = 0;
|
|
|
|
for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
|
|
max = std::max(values[valueNdx], max);
|
|
|
|
return max;
|
|
}
|
|
|
|
deUint64 findMedian (const vector<deUint64>& v)
|
|
{
|
|
vector<deUint64> values = v;
|
|
size_t n = values.size() / 2;
|
|
|
|
std::nth_element(values.begin(), values.begin() + n, values.end());
|
|
|
|
return values[n];
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
StateChangePerformanceCase::StateChangePerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, DrawType drawType, int drawCallCount, int triangleCount)
|
|
: tcu::TestCase (testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
|
|
, m_renderCtx (renderCtx)
|
|
, m_drawType (drawType)
|
|
, m_iterationCount (100)
|
|
, m_callCount (drawCallCount)
|
|
, m_triangleCount (triangleCount)
|
|
{
|
|
}
|
|
|
|
StateChangePerformanceCase::~StateChangePerformanceCase (void)
|
|
{
|
|
StateChangePerformanceCase::deinit();
|
|
}
|
|
|
|
void StateChangePerformanceCase::init (void)
|
|
{
|
|
if (m_drawType == DRAWTYPE_INDEXED_USER_PTR)
|
|
genIndices(m_indices, m_triangleCount);
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireIndexBuffers (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_indexBuffers.size() >= count)
|
|
return;
|
|
|
|
m_indexBuffers.reserve(count);
|
|
|
|
vector<GLushort> indices;
|
|
genIndices(indices, m_triangleCount);
|
|
|
|
while ((int)m_indexBuffers.size() < count)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(indices.size() * sizeof(GLushort)), &(indices[0]), GL_STATIC_DRAW);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
|
|
|
|
m_indexBuffers.push_back(buffer);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireCoordBuffers (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_coordBuffers.size() >= count)
|
|
return;
|
|
|
|
m_coordBuffers.reserve(count);
|
|
|
|
vector<GLfloat> coords;
|
|
genCoords(coords, m_triangleCount);
|
|
|
|
while ((int)m_coordBuffers.size() < count)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
|
|
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
|
|
gl.bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(coords.size() * sizeof(GLfloat)), &(coords[0]), GL_STATIC_DRAW);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
|
|
|
|
m_coordBuffers.push_back(buffer);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requirePrograms (int count)
|
|
{
|
|
if ((int)m_programs.size() >= count)
|
|
return;
|
|
|
|
m_programs.reserve(count);
|
|
|
|
while ((int)m_programs.size() < count)
|
|
{
|
|
string vertexShaderSource =
|
|
"attribute mediump vec2 a_coord;\n"
|
|
"varying mediump vec2 v_texCoord;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tv_texCoord = vec2(0.5) + 0.5" + de::toString(m_programs.size()) + " * a_coord.xy;\n"
|
|
"\tgl_Position = vec4(a_coord, 0.5, 1.0);\n"
|
|
"}";
|
|
|
|
string fragmentShaderSource =
|
|
"uniform sampler2D u_sampler;\n"
|
|
"varying mediump vec2 v_texCoord;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"\tgl_FragColor = vec4(1.0" + de::toString(m_programs.size()) + " * texture2D(u_sampler, v_texCoord).xyz, 1.0);\n"
|
|
"}";
|
|
|
|
glu::ShaderProgram* program = new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShaderSource) << glu::FragmentSource(fragmentShaderSource));
|
|
|
|
if (!program->isOk())
|
|
{
|
|
m_testCtx.getLog() << *program;
|
|
delete program;
|
|
TCU_FAIL("Compile failed");
|
|
}
|
|
|
|
m_programs.push_back(program);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireTextures (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
const int textureWidth = 64;
|
|
const int textureHeight = 64;
|
|
|
|
if ((int)m_textures.size() >= count)
|
|
return;
|
|
|
|
m_textures.reserve(count);
|
|
|
|
vector<deUint8> textureData;
|
|
genTextureData(textureData, textureWidth, textureHeight);
|
|
|
|
DE_ASSERT(textureData.size() == textureWidth * textureHeight * 4);
|
|
|
|
while ((int)m_textures.size() < count)
|
|
{
|
|
GLuint texture;
|
|
|
|
gl.genTextures(1, &texture);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures()");
|
|
|
|
gl.bindTexture(GL_TEXTURE_2D, texture);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
|
|
|
|
gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(textureData[0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D()");
|
|
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
|
|
gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
|
|
|
|
gl.bindTexture(GL_TEXTURE_2D, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
|
|
|
|
m_textures.push_back(texture);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireFramebuffers (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_framebuffers.size() >= count)
|
|
return;
|
|
|
|
m_framebuffers.reserve(count);
|
|
|
|
requireRenderbuffers(count);
|
|
|
|
while ((int)m_framebuffers.size() < count)
|
|
{
|
|
GLuint framebuffer;
|
|
|
|
gl.genFramebuffers(1, &framebuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers()");
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers[m_framebuffers.size()]);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
|
|
|
|
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffers[m_framebuffers.size()]);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer()");
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
|
|
|
|
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
|
|
|
|
m_framebuffers.push_back(framebuffer);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireRenderbuffers (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_renderbuffers.size() >= count)
|
|
return;
|
|
|
|
m_renderbuffers.reserve(count);
|
|
|
|
while ((int)m_renderbuffers.size() < count)
|
|
{
|
|
GLuint renderbuffer;
|
|
|
|
gl.genRenderbuffers(1, &renderbuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers()");
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
|
|
|
|
gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 24, 24);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage()");
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
|
|
|
|
m_renderbuffers.push_back(renderbuffer);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireSamplers (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_samplers.size() >= count)
|
|
return;
|
|
|
|
m_samplers.reserve(count);
|
|
|
|
while ((int)m_samplers.size() < count)
|
|
{
|
|
GLuint sampler;
|
|
gl.genSamplers(1, &sampler);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenSamplers()");
|
|
m_samplers.push_back(sampler);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::requireVertexArrays (int count)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if ((int)m_vertexArrays.size() >= count)
|
|
return;
|
|
|
|
m_vertexArrays.reserve(count);
|
|
|
|
while ((int)m_vertexArrays.size() < count)
|
|
{
|
|
GLuint vertexArray;
|
|
gl.genVertexArrays(1, &vertexArray);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays()");
|
|
m_vertexArrays.push_back(vertexArray);
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::deinit (void)
|
|
{
|
|
m_indices.clear();
|
|
m_interleavedResults.clear();
|
|
m_batchedResults.clear();
|
|
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if (!m_indexBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_indexBuffers.size(), &(m_indexBuffers[0]));
|
|
m_indexBuffers.clear();
|
|
}
|
|
|
|
if (!m_coordBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_coordBuffers.size(), &(m_coordBuffers[0]));
|
|
m_coordBuffers.clear();
|
|
}
|
|
|
|
if (!m_textures.empty())
|
|
{
|
|
gl.deleteTextures((GLsizei)m_textures.size(), &(m_textures[0]));
|
|
m_textures.clear();
|
|
}
|
|
|
|
if (!m_framebuffers.empty())
|
|
{
|
|
gl.deleteFramebuffers((GLsizei)m_framebuffers.size(), &(m_framebuffers[0]));
|
|
m_framebuffers.clear();
|
|
}
|
|
|
|
if (!m_renderbuffers.empty())
|
|
{
|
|
gl.deleteRenderbuffers((GLsizei)m_renderbuffers.size(), &(m_renderbuffers[0]));
|
|
m_renderbuffers.clear();
|
|
}
|
|
|
|
if (!m_samplers.empty())
|
|
{
|
|
gl.deleteSamplers((GLsizei)m_samplers.size(), &m_samplers[0]);
|
|
m_samplers.clear();
|
|
}
|
|
|
|
if (!m_vertexArrays.empty())
|
|
{
|
|
gl.deleteVertexArrays((GLsizei)m_vertexArrays.size(), &m_vertexArrays[0]);
|
|
m_vertexArrays.clear();
|
|
}
|
|
|
|
for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
|
|
{
|
|
delete m_programs[programNdx];
|
|
m_programs[programNdx] = NULL;
|
|
}
|
|
m_programs.clear();
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::logAndSetTestResult (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
ResultStats interleaved = calculateStats(m_interleavedResults);
|
|
ResultStats batched = calculateStats(m_batchedResults);
|
|
|
|
log << TestLog::Message << "Interleaved mean: " << interleaved.mean << TestLog::EndMessage;
|
|
log << TestLog::Message << "Interleaved median: " << interleaved.median << TestLog::EndMessage;
|
|
log << TestLog::Message << "Interleaved variance: " << interleaved.variance << TestLog::EndMessage;
|
|
log << TestLog::Message << "Interleaved min: " << interleaved.min << TestLog::EndMessage;
|
|
log << TestLog::Message << "Interleaved max: " << interleaved.max << TestLog::EndMessage;
|
|
|
|
log << TestLog::Message << "Batched mean: " << batched.mean << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched median: " << batched.median << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched variance: " << batched.variance << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched min: " << batched.min << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched max: " << batched.max << TestLog::EndMessage;
|
|
|
|
log << TestLog::Message << "Batched/Interleaved mean ratio: " << (interleaved.mean/batched.mean) << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched/Interleaved median ratio: " << (interleaved.median/batched.median) << TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)(((double)interleaved.median) / batched.median), 2).c_str());
|
|
}
|
|
|
|
tcu::TestCase::IterateResult StateChangePerformanceCase::iterate (void)
|
|
{
|
|
if (m_interleavedResults.empty() && m_batchedResults.empty())
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
log << TestLog::Message << "Draw call count: " << m_callCount << TestLog::EndMessage;
|
|
log << TestLog::Message << "Per call triangle count: " << m_triangleCount << TestLog::EndMessage;
|
|
}
|
|
|
|
// \note [mika] Interleave sampling to balance effects of powerstate etc.
|
|
if ((int)m_interleavedResults.size() < m_iterationCount && m_batchedResults.size() >= m_interleavedResults.size())
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
deUint64 resBeginUs = 0;
|
|
deUint64 resEndUs = 0;
|
|
|
|
setupInitialState(gl);
|
|
gl.finish();
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
|
|
|
|
// Render result
|
|
resBeginUs = deGetMicroseconds();
|
|
|
|
renderTest(gl);
|
|
|
|
gl.finish();
|
|
resEndUs = deGetMicroseconds();
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
|
|
|
|
m_interleavedResults.push_back(resEndUs - resBeginUs);
|
|
|
|
return CONTINUE;
|
|
}
|
|
else if ((int)m_batchedResults.size() < m_iterationCount)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
deUint64 refBeginUs = 0;
|
|
deUint64 refEndUs = 0;
|
|
|
|
setupInitialState(gl);
|
|
gl.finish();
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
|
|
|
|
// Render reference
|
|
refBeginUs = deGetMicroseconds();
|
|
|
|
renderReference(gl);
|
|
|
|
gl.finish();
|
|
refEndUs = deGetMicroseconds();
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
|
|
|
|
m_batchedResults.push_back(refEndUs - refBeginUs);
|
|
|
|
return CONTINUE;
|
|
}
|
|
else
|
|
{
|
|
logAndSetTestResult();
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
void StateChangePerformanceCase::callDraw (const glw::Functions& gl)
|
|
{
|
|
switch (m_drawType)
|
|
{
|
|
case DRAWTYPE_NOT_INDEXED: gl.drawArrays(GL_TRIANGLES, 0, m_triangleCount * 3); break;
|
|
case DRAWTYPE_INDEXED_USER_PTR: gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, &m_indices[0]); break;
|
|
case DRAWTYPE_INDEXED_BUFFER: gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, NULL); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
// StateChangeCallPerformanceCase
|
|
|
|
StateChangeCallPerformanceCase::StateChangeCallPerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description)
|
|
: tcu::TestCase (testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
|
|
, m_renderCtx (renderCtx)
|
|
, m_iterationCount (100)
|
|
, m_callCount (1000)
|
|
{
|
|
}
|
|
|
|
StateChangeCallPerformanceCase::~StateChangeCallPerformanceCase (void)
|
|
{
|
|
}
|
|
|
|
void StateChangeCallPerformanceCase::executeTest (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
deUint64 beginTimeUs = 0;
|
|
deUint64 endTimeUs = 0;
|
|
|
|
beginTimeUs = deGetMicroseconds();
|
|
|
|
execCalls(gl, (int)m_results.size(), m_callCount);
|
|
|
|
endTimeUs = deGetMicroseconds();
|
|
|
|
m_results.push_back(endTimeUs - beginTimeUs);
|
|
}
|
|
|
|
void StateChangeCallPerformanceCase::logTestCase (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
log << TestLog::Message << "Iteration count: " << m_iterationCount << TestLog::EndMessage;
|
|
log << TestLog::Message << "Per iteration call count: " << m_callCount << TestLog::EndMessage;
|
|
}
|
|
|
|
double calculateAverage (const vector<deUint64>& values)
|
|
{
|
|
deUint64 sum = 0;
|
|
|
|
for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
|
|
sum += values[valueNdx];
|
|
|
|
return ((double)sum) / (double)values.size();
|
|
}
|
|
|
|
void StateChangeCallPerformanceCase::logAndSetTestResult (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
deUint64 minUs = findMin(m_results);
|
|
deUint64 maxUs = findMax(m_results);
|
|
deUint64 medianUs = findMedian(m_results);
|
|
double avgIterationUs = calculateAverage(m_results);
|
|
double avgCallUs = avgIterationUs / m_callCount;
|
|
double varIteration = calculateVariance(m_results, avgIterationUs);
|
|
double avgMedianCallUs = ((double)medianUs)/m_callCount;
|
|
|
|
log << TestLog::Message << "Min iteration time: " << minUs << "us" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Max iteration time: " << maxUs << "us" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Average iteration time: " << avgIterationUs << "us" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Iteration variance time: " << varIteration << TestLog::EndMessage;
|
|
log << TestLog::Message << "Median iteration time: " << medianUs << "us" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Average call time: " << avgCallUs << "us" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Average call time for median iteration: " << avgMedianCallUs << "us" << TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)avgMedianCallUs, 3).c_str());
|
|
}
|
|
|
|
tcu::TestCase::IterateResult StateChangeCallPerformanceCase::iterate (void)
|
|
{
|
|
if (m_results.empty())
|
|
logTestCase();
|
|
|
|
if ((int)m_results.size() < m_iterationCount)
|
|
{
|
|
executeTest();
|
|
GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Unexpected error");
|
|
return CONTINUE;
|
|
}
|
|
else
|
|
{
|
|
logAndSetTestResult();
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
} // gls
|
|
} // deqp
|