You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1091 lines
33 KiB
1091 lines
33 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 2.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 Draw call batching performance tests
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es2pDrawCallBatchingTests.hpp"
|
|
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
|
|
#include "glwDefs.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
|
|
#include "tcuTestLog.hpp"
|
|
|
|
#include "deRandom.hpp"
|
|
#include "deStringUtil.hpp"
|
|
|
|
#include "deFile.h"
|
|
#include "deString.h"
|
|
#include "deClock.h"
|
|
#include "deThread.h"
|
|
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
using tcu::TestLog;
|
|
|
|
using namespace glw;
|
|
|
|
using std::vector;
|
|
using std::string;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles2
|
|
{
|
|
namespace Performance
|
|
{
|
|
|
|
namespace
|
|
{
|
|
const int CALIBRATION_SAMPLE_COUNT = 34;
|
|
|
|
class DrawCallBatchingTest : public tcu::TestCase
|
|
{
|
|
public:
|
|
struct TestSpec
|
|
{
|
|
bool useStaticBuffer;
|
|
int staticAttributeCount;
|
|
|
|
bool useDynamicBuffer;
|
|
int dynamicAttributeCount;
|
|
|
|
int triangleCount;
|
|
int drawCallCount;
|
|
|
|
bool useDrawElements;
|
|
bool useIndexBuffer;
|
|
bool dynamicIndices;
|
|
};
|
|
|
|
DrawCallBatchingTest (Context& context, const char* name, const char* description, const TestSpec& spec);
|
|
~DrawCallBatchingTest (void);
|
|
|
|
void init (void);
|
|
void deinit (void);
|
|
IterateResult iterate (void);
|
|
|
|
private:
|
|
enum State
|
|
{
|
|
STATE_LOG_INFO = 0,
|
|
STATE_WARMUP_BATCHED,
|
|
STATE_WARMUP_UNBATCHED,
|
|
STATE_CALC_CALIBRATION,
|
|
STATE_SAMPLE
|
|
};
|
|
|
|
State m_state;
|
|
|
|
glu::RenderContext& m_renderCtx;
|
|
de::Random m_rnd;
|
|
int m_sampleIteration;
|
|
|
|
int m_unbatchedSampleCount;
|
|
int m_batchedSampleCount;
|
|
|
|
TestSpec m_spec;
|
|
|
|
glu::ShaderProgram* m_program;
|
|
|
|
vector<deUint8> m_dynamicIndexData;
|
|
vector<deUint8> m_staticIndexData;
|
|
|
|
vector<GLuint> m_unbatchedDynamicIndexBuffers;
|
|
GLuint m_batchedDynamicIndexBuffer;
|
|
|
|
GLuint m_unbatchedStaticIndexBuffer;
|
|
GLuint m_batchedStaticIndexBuffer;
|
|
|
|
vector<vector<deInt8> > m_staticAttributeDatas;
|
|
vector<vector<deInt8> > m_dynamicAttributeDatas;
|
|
|
|
vector<GLuint> m_batchedStaticBuffers;
|
|
vector<GLuint> m_unbatchedStaticBuffers;
|
|
|
|
vector<GLuint> m_batchedDynamicBuffers;
|
|
vector<vector<GLuint> > m_unbatchedDynamicBuffers;
|
|
|
|
vector<deUint64> m_unbatchedSamplesUs;
|
|
vector<deUint64> m_batchedSamplesUs;
|
|
|
|
void logTestInfo (void);
|
|
|
|
deUint64 renderUnbatched (void);
|
|
deUint64 renderBatched (void);
|
|
|
|
void createIndexData (void);
|
|
void createIndexBuffer (void);
|
|
|
|
void createShader (void);
|
|
void createAttributeDatas (void);
|
|
void createArrayBuffers (void);
|
|
};
|
|
|
|
DrawCallBatchingTest::DrawCallBatchingTest (Context& context, const char* name, const char* description, const TestSpec& spec)
|
|
: tcu::TestCase (context.getTestContext(), tcu::NODETYPE_PERFORMANCE, name, description)
|
|
, m_state (STATE_LOG_INFO)
|
|
, m_renderCtx (context.getRenderContext())
|
|
, m_rnd (deStringHash(name))
|
|
, m_sampleIteration (0)
|
|
, m_unbatchedSampleCount (CALIBRATION_SAMPLE_COUNT)
|
|
, m_batchedSampleCount (CALIBRATION_SAMPLE_COUNT)
|
|
, m_spec (spec)
|
|
, m_program (NULL)
|
|
, m_batchedDynamicIndexBuffer (0)
|
|
, m_unbatchedStaticIndexBuffer (0)
|
|
, m_batchedStaticIndexBuffer (0)
|
|
{
|
|
}
|
|
|
|
DrawCallBatchingTest::~DrawCallBatchingTest (void)
|
|
{
|
|
deinit();
|
|
}
|
|
|
|
void DrawCallBatchingTest::createIndexData (void)
|
|
{
|
|
if (m_spec.dynamicIndices)
|
|
{
|
|
for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
|
|
{
|
|
for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
|
|
{
|
|
m_dynamicIndexData.push_back(deUint8(triangleNdx * 3));
|
|
m_dynamicIndexData.push_back(deUint8(triangleNdx * 3 + 1));
|
|
m_dynamicIndexData.push_back(deUint8(triangleNdx * 3 + 2));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
|
|
{
|
|
for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
|
|
{
|
|
m_staticIndexData.push_back(deUint8(triangleNdx * 3));
|
|
m_staticIndexData.push_back(deUint8(triangleNdx * 3 + 1));
|
|
m_staticIndexData.push_back(deUint8(triangleNdx * 3 + 2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawCallBatchingTest::createShader (void)
|
|
{
|
|
std::ostringstream vertexShader;
|
|
std::ostringstream fragmentShader;
|
|
|
|
for (int attributeNdx = 0; attributeNdx < m_spec.staticAttributeCount; attributeNdx++)
|
|
vertexShader << "attribute mediump vec4 a_static" << attributeNdx << ";\n";
|
|
|
|
if (m_spec.staticAttributeCount > 0 && m_spec.dynamicAttributeCount > 0)
|
|
vertexShader << "\n";
|
|
|
|
for (int attributeNdx = 0; attributeNdx < m_spec.dynamicAttributeCount; attributeNdx++)
|
|
vertexShader << "attribute mediump vec4 a_dyn" << attributeNdx << ";\n";
|
|
|
|
vertexShader
|
|
<< "\n"
|
|
<< "varying mediump vec4 v_color;\n"
|
|
<< "\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n";
|
|
|
|
vertexShader << "\tv_color = ";
|
|
|
|
bool first = true;
|
|
|
|
for (int attributeNdx = 0; attributeNdx < m_spec.staticAttributeCount; attributeNdx++)
|
|
{
|
|
if (!first)
|
|
vertexShader << " + ";
|
|
first = false;
|
|
|
|
vertexShader << "a_static" << attributeNdx;
|
|
}
|
|
|
|
for (int attributeNdx = 0; attributeNdx < m_spec.dynamicAttributeCount; attributeNdx++)
|
|
{
|
|
if (!first)
|
|
vertexShader << " + ";
|
|
first = false;
|
|
|
|
vertexShader << "a_dyn" << attributeNdx;
|
|
}
|
|
|
|
vertexShader << ";\n";
|
|
|
|
if (m_spec.dynamicAttributeCount > 0)
|
|
vertexShader << "\tgl_Position = a_dyn0;\n";
|
|
else
|
|
vertexShader << "\tgl_Position = a_static0;\n";
|
|
|
|
vertexShader
|
|
<< "}";
|
|
|
|
fragmentShader
|
|
<< "varying mediump vec4 v_color;\n"
|
|
<< "\n"
|
|
<< "void main(void)\n"
|
|
<< "{\n"
|
|
<< "\tgl_FragColor = v_color;\n"
|
|
<< "}\n";
|
|
|
|
m_program = new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShader.str()) << glu::FragmentSource(fragmentShader.str()));
|
|
|
|
m_testCtx.getLog() << (*m_program);
|
|
TCU_CHECK(m_program->isOk());
|
|
}
|
|
|
|
void DrawCallBatchingTest::createAttributeDatas (void)
|
|
{
|
|
// Generate data for static attributes
|
|
for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
|
|
{
|
|
vector<deInt8> data;
|
|
|
|
if (m_spec.dynamicAttributeCount == 0 && attribute == 0)
|
|
{
|
|
data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
|
|
|
|
for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
|
|
{
|
|
int sign = (m_spec.triangleCount % 2 == 1 || i % 2 == 0 ? 1 : -1);
|
|
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
|
|
|
|
for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
|
|
data.push_back((deInt8)m_rnd.getUint32());
|
|
}
|
|
|
|
m_staticAttributeDatas.push_back(data);
|
|
}
|
|
|
|
// Generate data for dynamic attributes
|
|
for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
|
|
{
|
|
vector<deInt8> data;
|
|
|
|
if (attribute == 0)
|
|
{
|
|
data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
|
|
|
|
for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
|
|
{
|
|
int sign = (i % 2 == 0 ? 1 : -1);
|
|
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(deInt8(-127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(deInt8(127 * sign));
|
|
data.push_back(0);
|
|
data.push_back(127);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
|
|
|
|
for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
|
|
data.push_back((deInt8)m_rnd.getUint32());
|
|
}
|
|
|
|
m_dynamicAttributeDatas.push_back(data);
|
|
}
|
|
}
|
|
|
|
void DrawCallBatchingTest::createArrayBuffers (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if (m_spec.useStaticBuffer)
|
|
{
|
|
// Upload static attributes for batched
|
|
for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_staticAttributeDatas[attribute][0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating static buffer failed");
|
|
|
|
m_batchedStaticBuffers.push_back(buffer);
|
|
}
|
|
|
|
// Upload static attributes for unbatched
|
|
for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount, &(m_staticAttributeDatas[attribute][0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating static buffer failed");
|
|
|
|
m_unbatchedStaticBuffers.push_back(buffer);
|
|
}
|
|
}
|
|
|
|
if (m_spec.useDynamicBuffer)
|
|
{
|
|
// Upload dynamic attributes for batched
|
|
for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
|
|
|
|
m_batchedDynamicBuffers.push_back(buffer);
|
|
}
|
|
|
|
// Upload dynamic attributes for unbatched
|
|
for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
|
|
{
|
|
vector<GLuint> buffers;
|
|
|
|
for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
|
|
|
|
buffers.push_back(buffer);
|
|
}
|
|
|
|
m_unbatchedDynamicBuffers.push_back(buffers);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawCallBatchingTest::createIndexBuffer (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
if (m_spec.dynamicIndices)
|
|
{
|
|
for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount, &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
|
|
|
|
m_unbatchedDynamicIndexBuffers.push_back(buffer);
|
|
}
|
|
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicIndexData[0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
|
|
|
|
m_batchedDynamicIndexBuffer = buffer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_staticIndexData[0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
|
|
|
|
m_batchedStaticIndexBuffer = buffer;
|
|
}
|
|
|
|
{
|
|
GLuint buffer;
|
|
|
|
gl.genBuffers(1, &buffer);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
|
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount, &(m_staticIndexData[0]), GL_STATIC_DRAW);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
|
|
|
|
m_unbatchedStaticIndexBuffer = buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawCallBatchingTest::init (void)
|
|
{
|
|
createShader();
|
|
createAttributeDatas();
|
|
createArrayBuffers();
|
|
|
|
if (m_spec.useDrawElements)
|
|
{
|
|
createIndexData();
|
|
|
|
if (m_spec.useIndexBuffer)
|
|
createIndexBuffer();
|
|
}
|
|
}
|
|
|
|
void DrawCallBatchingTest::deinit (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
delete m_program;
|
|
m_program = NULL;
|
|
|
|
m_dynamicIndexData = vector<deUint8>();
|
|
m_staticIndexData = vector<deUint8>();
|
|
|
|
if (!m_unbatchedDynamicIndexBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_unbatchedDynamicIndexBuffers.size(), &(m_unbatchedDynamicIndexBuffers[0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_unbatchedDynamicIndexBuffers = vector<GLuint>();
|
|
}
|
|
|
|
if (m_batchedDynamicIndexBuffer)
|
|
{
|
|
gl.deleteBuffers((GLsizei)1, &m_batchedDynamicIndexBuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_batchedDynamicIndexBuffer = 0;
|
|
}
|
|
|
|
if (m_unbatchedStaticIndexBuffer)
|
|
{
|
|
gl.deleteBuffers((GLsizei)1, &m_unbatchedStaticIndexBuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_unbatchedStaticIndexBuffer = 0;
|
|
}
|
|
|
|
if (m_batchedStaticIndexBuffer)
|
|
{
|
|
gl.deleteBuffers((GLsizei)1, &m_batchedStaticIndexBuffer);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_batchedStaticIndexBuffer = 0;
|
|
}
|
|
|
|
m_staticAttributeDatas = vector<vector<deInt8> >();
|
|
m_dynamicAttributeDatas = vector<vector<deInt8> >();
|
|
|
|
if (!m_batchedStaticBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_batchedStaticBuffers.size(), &(m_batchedStaticBuffers[0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_batchedStaticBuffers = vector<GLuint>();
|
|
}
|
|
|
|
if (!m_unbatchedStaticBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_unbatchedStaticBuffers.size(), &(m_unbatchedStaticBuffers[0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_unbatchedStaticBuffers = vector<GLuint>();
|
|
}
|
|
|
|
if (!m_batchedDynamicBuffers.empty())
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_batchedDynamicBuffers.size(), &(m_batchedDynamicBuffers[0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
|
|
m_batchedDynamicBuffers = vector<GLuint>();
|
|
}
|
|
|
|
for (int i = 0; i < (int)m_unbatchedDynamicBuffers.size(); i++)
|
|
{
|
|
gl.deleteBuffers((GLsizei)m_unbatchedDynamicBuffers[i].size(), &(m_unbatchedDynamicBuffers[i][0]));
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
|
|
}
|
|
|
|
m_unbatchedDynamicBuffers = vector<vector<GLuint> >();
|
|
|
|
m_unbatchedSamplesUs = vector<deUint64>();
|
|
m_batchedSamplesUs = vector<deUint64>();
|
|
}
|
|
|
|
deUint64 DrawCallBatchingTest::renderUnbatched (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
deUint64 beginUs = 0;
|
|
deUint64 endUs = 0;
|
|
vector<GLint> dynamicAttributeLocations;
|
|
|
|
gl.viewport(0, 0, 32, 32);
|
|
gl.useProgram(m_program->getProgram());
|
|
|
|
// Setup static buffers
|
|
for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
|
|
|
|
gl.enableVertexAttribArray(location);
|
|
|
|
if (m_spec.useStaticBuffer)
|
|
{
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedStaticBuffers[attribNdx]);
|
|
gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
|
|
}
|
|
|
|
// Get locations of dynamic attributes
|
|
for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
|
|
|
|
gl.enableVertexAttribArray(location);
|
|
dynamicAttributeLocations.push_back(location);
|
|
}
|
|
|
|
if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedStaticIndexBuffer);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
|
|
|
|
gl.finish();
|
|
|
|
beginUs = deGetMicroseconds();
|
|
|
|
for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
|
|
{
|
|
for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
|
|
{
|
|
if (m_spec.useDynamicBuffer)
|
|
{
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedDynamicBuffers[attribNdx][drawNdx]);
|
|
gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0, NULL);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0, &(m_dynamicAttributeDatas[attribNdx][m_spec.triangleCount * 3 * drawNdx * 4]));
|
|
}
|
|
|
|
if (m_spec.useDrawElements)
|
|
{
|
|
if (m_spec.useIndexBuffer)
|
|
{
|
|
if (m_spec.dynamicIndices)
|
|
{
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedDynamicIndexBuffers[drawNdx]);
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (m_spec.dynamicIndices)
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]));
|
|
else
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, &(m_staticIndexData[0]));
|
|
}
|
|
}
|
|
else
|
|
gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount);
|
|
}
|
|
|
|
gl.finish();
|
|
|
|
endUs = deGetMicroseconds();
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Unbatched rendering failed");
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
|
|
gl.disableVertexAttribArray(location);
|
|
}
|
|
|
|
for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
|
|
gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after unbatched rendering");
|
|
|
|
return endUs - beginUs;
|
|
}
|
|
|
|
deUint64 DrawCallBatchingTest::renderBatched (void)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
deUint64 beginUs = 0;
|
|
deUint64 endUs = 0;
|
|
vector<GLint> dynamicAttributeLocations;
|
|
|
|
gl.viewport(0, 0, 32, 32);
|
|
gl.useProgram(m_program->getProgram());
|
|
|
|
// Setup static buffers
|
|
for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
|
|
|
|
gl.enableVertexAttribArray(location);
|
|
|
|
if (m_spec.useStaticBuffer)
|
|
{
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedStaticBuffers[attribNdx]);
|
|
gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
|
|
}
|
|
|
|
// Get locations of dynamic attributes
|
|
for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
|
|
|
|
gl.enableVertexAttribArray(location);
|
|
dynamicAttributeLocations.push_back(location);
|
|
}
|
|
|
|
if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedStaticIndexBuffer);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
|
|
|
|
gl.finish();
|
|
|
|
beginUs = deGetMicroseconds();
|
|
|
|
for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
|
|
{
|
|
if (m_spec.useDynamicBuffer)
|
|
{
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedDynamicBuffers[attribute]);
|
|
gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0, NULL);
|
|
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0, &(m_dynamicAttributeDatas[attribute][0]));
|
|
}
|
|
|
|
if (m_spec.useDrawElements)
|
|
{
|
|
if (m_spec.useIndexBuffer)
|
|
{
|
|
if (m_spec.dynamicIndices)
|
|
{
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedDynamicIndexBuffer);
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (m_spec.dynamicIndices)
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, &(m_dynamicIndexData[0]));
|
|
else
|
|
gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, &(m_staticIndexData[0]));
|
|
}
|
|
}
|
|
else
|
|
gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount * m_spec.drawCallCount);
|
|
|
|
gl.finish();
|
|
|
|
endUs = deGetMicroseconds();
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Batched rendering failed");
|
|
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
|
|
{
|
|
GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
|
|
gl.disableVertexAttribArray(location);
|
|
}
|
|
|
|
for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
|
|
gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
|
|
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after batched rendering");
|
|
|
|
return endUs - beginUs;
|
|
}
|
|
|
|
struct Statistics
|
|
{
|
|
double mean;
|
|
double standardDeviation;
|
|
double standardErrorOfMean;
|
|
};
|
|
|
|
Statistics calculateStats (const vector<deUint64>& samples)
|
|
{
|
|
double mean = 0.0;
|
|
|
|
for (int i = 0; i < (int)samples.size(); i++)
|
|
mean += (double)samples[i];
|
|
|
|
mean /= (double)samples.size();
|
|
|
|
double standardDeviation = 0.0;
|
|
|
|
for (int i = 0; i < (int)samples.size(); i++)
|
|
{
|
|
double x = (double)samples[i];
|
|
standardDeviation += (x - mean) * (x - mean);
|
|
}
|
|
|
|
standardDeviation /= (double)samples.size();
|
|
standardDeviation = std::sqrt(standardDeviation);
|
|
|
|
double standardErrorOfMean = standardDeviation / std::sqrt((double)samples.size());
|
|
|
|
Statistics stats;
|
|
|
|
stats.mean = mean;
|
|
stats.standardDeviation = standardDeviation;
|
|
stats.standardErrorOfMean = standardErrorOfMean;
|
|
|
|
return stats;
|
|
}
|
|
|
|
void DrawCallBatchingTest::logTestInfo (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
tcu::ScopedLogSection section (log, "Test info", "Test info");
|
|
|
|
log << TestLog::Message << "Rendering using " << (m_spec.useDrawElements ? "glDrawElements()" : "glDrawArrays()") << "." << TestLog::EndMessage;
|
|
|
|
if (m_spec.useDrawElements)
|
|
log << TestLog::Message << "Using " << (m_spec.dynamicIndices ? "dynamic " : "") << "indices from " << (m_spec.useIndexBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
|
|
|
|
if (m_spec.staticAttributeCount > 0)
|
|
log << TestLog::Message << "Using " << m_spec.staticAttributeCount << " static attribute" << (m_spec.staticAttributeCount > 1 ? "s" : "") << " from " << (m_spec.useStaticBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
|
|
|
|
if (m_spec.dynamicAttributeCount > 0)
|
|
log << TestLog::Message << "Using " << m_spec.dynamicAttributeCount << " dynamic attribute" << (m_spec.dynamicAttributeCount > 1 ? "s" : "") << " from " << (m_spec.useDynamicBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
|
|
|
|
log << TestLog::Message << "Rendering " << m_spec.drawCallCount << " draw calls with " << m_spec.triangleCount << " triangles per call." << TestLog::EndMessage;
|
|
}
|
|
|
|
tcu::TestCase::IterateResult DrawCallBatchingTest::iterate (void)
|
|
{
|
|
if (m_state == STATE_LOG_INFO)
|
|
{
|
|
logTestInfo();
|
|
m_state = STATE_WARMUP_BATCHED;
|
|
}
|
|
else if (m_state == STATE_WARMUP_BATCHED)
|
|
{
|
|
renderBatched();
|
|
m_state = STATE_WARMUP_UNBATCHED;
|
|
}
|
|
else if (m_state == STATE_WARMUP_UNBATCHED)
|
|
{
|
|
renderUnbatched();
|
|
m_state = STATE_SAMPLE;
|
|
}
|
|
else if (m_state == STATE_SAMPLE)
|
|
{
|
|
if ((int)m_unbatchedSamplesUs.size() < m_unbatchedSampleCount && ((double)m_unbatchedSamplesUs.size() / ((double)m_unbatchedSampleCount) < (double)m_batchedSamplesUs.size() / ((double)m_batchedSampleCount) || (int)m_batchedSamplesUs.size() >= m_batchedSampleCount))
|
|
m_unbatchedSamplesUs.push_back(renderUnbatched());
|
|
else if ((int)m_batchedSamplesUs.size() < m_batchedSampleCount)
|
|
m_batchedSamplesUs.push_back(renderBatched());
|
|
else
|
|
m_state = STATE_CALC_CALIBRATION;
|
|
}
|
|
else if (m_state == STATE_CALC_CALIBRATION)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
tcu::ScopedLogSection section(log, ("Sampling iteration " + de::toString(m_sampleIteration)).c_str(), ("Sampling iteration " + de::toString(m_sampleIteration)).c_str());
|
|
const double targetSEM = 0.02;
|
|
const double limitSEM = 0.025;
|
|
|
|
Statistics unbatchedStats = calculateStats(m_unbatchedSamplesUs);
|
|
Statistics batchedStats = calculateStats(m_batchedSamplesUs);
|
|
|
|
log << TestLog::Message << "Batched samples; Count: " << m_batchedSamplesUs.size() << ", Mean: " << batchedStats.mean << "us, Standard deviation: " << batchedStats.standardDeviation << "us, Standard error of mean: " << batchedStats.standardErrorOfMean << "us(" << (batchedStats.standardErrorOfMean/batchedStats.mean) << ")" << TestLog::EndMessage;
|
|
log << TestLog::Message << "Unbatched samples; Count: " << m_unbatchedSamplesUs.size() << ", Mean: " << unbatchedStats.mean << "us, Standard deviation: " << unbatchedStats.standardDeviation << "us, Standard error of mean: " << unbatchedStats.standardErrorOfMean << "us(" << (unbatchedStats.standardErrorOfMean/unbatchedStats.mean) << ")" << TestLog::EndMessage;
|
|
|
|
if (m_sampleIteration > 2 || (m_sampleIteration > 0 && (unbatchedStats.standardErrorOfMean/unbatchedStats.mean) + (batchedStats.standardErrorOfMean/batchedStats.mean) <= 2.0 * limitSEM))
|
|
{
|
|
if (m_sampleIteration > 2)
|
|
log << TestLog::Message << "Maximum iteration count reached." << TestLog::EndMessage;
|
|
|
|
log << TestLog::Message << "Standard errors in target range." << TestLog::EndMessage;
|
|
log << TestLog::Message << "Batched/Unbatched ratio: " << (batchedStats.mean / unbatchedStats.mean) << TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)(batchedStats.mean/unbatchedStats.mean), 1).c_str());
|
|
return STOP;
|
|
}
|
|
else
|
|
{
|
|
if ((unbatchedStats.standardErrorOfMean/unbatchedStats.mean) > targetSEM)
|
|
log << TestLog::Message << "Unbatched standard error of mean outside of range." << TestLog::EndMessage;
|
|
|
|
if ((batchedStats.standardErrorOfMean/batchedStats.mean) > targetSEM)
|
|
log << TestLog::Message << "Batched standard error of mean outside of range." << TestLog::EndMessage;
|
|
|
|
if (unbatchedStats.standardDeviation > 0.0)
|
|
{
|
|
double x = (unbatchedStats.standardDeviation / unbatchedStats.mean) / targetSEM;
|
|
m_unbatchedSampleCount = std::max((int)m_unbatchedSamplesUs.size(), (int)(x * x));
|
|
}
|
|
else
|
|
m_unbatchedSampleCount = (int)m_unbatchedSamplesUs.size();
|
|
|
|
if (batchedStats.standardDeviation > 0.0)
|
|
{
|
|
double x = (batchedStats.standardDeviation / batchedStats.mean) / targetSEM;
|
|
m_batchedSampleCount = std::max((int)m_batchedSamplesUs.size(), (int)(x * x));
|
|
}
|
|
else
|
|
m_batchedSampleCount = (int)m_batchedSamplesUs.size();
|
|
|
|
m_batchedSamplesUs.clear();
|
|
m_unbatchedSamplesUs.clear();
|
|
|
|
m_sampleIteration++;
|
|
m_state = STATE_SAMPLE;
|
|
}
|
|
}
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
return CONTINUE;
|
|
}
|
|
|
|
string specToName (const DrawCallBatchingTest::TestSpec& spec)
|
|
{
|
|
std::ostringstream stream;
|
|
|
|
DE_ASSERT(!spec.useStaticBuffer || spec.staticAttributeCount > 0);
|
|
DE_ASSERT(!spec.useDynamicBuffer|| spec.dynamicAttributeCount > 0);
|
|
|
|
if (spec.staticAttributeCount > 0)
|
|
stream << spec.staticAttributeCount << "_static_";
|
|
|
|
if (spec.useStaticBuffer)
|
|
stream << (spec.staticAttributeCount == 1 ? "buffer_" : "buffers_");
|
|
|
|
if (spec.dynamicAttributeCount > 0)
|
|
stream << spec.dynamicAttributeCount << "_dynamic_";
|
|
|
|
if (spec.useDynamicBuffer)
|
|
stream << (spec.dynamicAttributeCount == 1 ? "buffer_" : "buffers_");
|
|
|
|
stream << spec.triangleCount << "_triangles";
|
|
|
|
return stream.str();
|
|
}
|
|
|
|
string specToDescrpition (const DrawCallBatchingTest::TestSpec& spec)
|
|
{
|
|
DE_UNREF(spec);
|
|
return "Test performance of batched rendering against non-batched rendering.";
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
DrawCallBatchingTests::DrawCallBatchingTests (Context& context)
|
|
: TestCaseGroup(context, "draw_call_batching", "Draw call batching performance tests.")
|
|
{
|
|
}
|
|
|
|
DrawCallBatchingTests::~DrawCallBatchingTests (void)
|
|
{
|
|
}
|
|
|
|
void DrawCallBatchingTests::init (void)
|
|
{
|
|
int drawCallCounts[] = {
|
|
10, 100
|
|
};
|
|
|
|
int triangleCounts[] = {
|
|
2, 10
|
|
};
|
|
|
|
int staticAttributeCounts[] = {
|
|
1, 0, 4, 8, 0
|
|
};
|
|
|
|
int dynamicAttributeCounts[] = {
|
|
0, 1, 4, 0, 8
|
|
};
|
|
|
|
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(staticAttributeCounts) == DE_LENGTH_OF_ARRAY(dynamicAttributeCounts));
|
|
|
|
for (int drawType = 0; drawType < 2; drawType++)
|
|
{
|
|
bool drawElements = (drawType == 1);
|
|
|
|
for (int indexBufferNdx = 0; indexBufferNdx < 2; indexBufferNdx++)
|
|
{
|
|
bool useIndexBuffer = (indexBufferNdx == 1);
|
|
|
|
if (useIndexBuffer && !drawElements)
|
|
continue;
|
|
|
|
for (int dynamicIndexNdx = 0; dynamicIndexNdx < 2; dynamicIndexNdx++)
|
|
{
|
|
bool dynamicIndices = (dynamicIndexNdx == 1);
|
|
|
|
if (dynamicIndices && !drawElements)
|
|
continue;
|
|
|
|
if (dynamicIndices && !useIndexBuffer)
|
|
continue;
|
|
|
|
TestCaseGroup* drawTypeGroup = new TestCaseGroup(m_context, (string(dynamicIndices ? "dynamic_" : "") + (useIndexBuffer ? "buffer_" : "" ) + (drawElements ? "draw_elements" : "draw_arrays")).c_str(), (string("Test batched rendering with ") + (drawElements ? "draw_elements" : "draw_arrays")).c_str());
|
|
|
|
addChild(drawTypeGroup);
|
|
|
|
for (int drawCallCountNdx = 0; drawCallCountNdx < DE_LENGTH_OF_ARRAY(drawCallCounts); drawCallCountNdx++)
|
|
{
|
|
int drawCallCount = drawCallCounts[drawCallCountNdx];
|
|
|
|
TestCaseGroup* callCountGroup = new TestCaseGroup(m_context, (de::toString(drawCallCount) + (drawCallCount == 1 ? "_draw" : "_draws")).c_str(), ("Test batched rendering performance with " + de::toString(drawCallCount) + " draw calls.").c_str());
|
|
TestCaseGroup* attributeCount1Group = new TestCaseGroup(m_context, "1_attribute", "Test draw call batching with 1 attribute.");
|
|
TestCaseGroup* attributeCount8Group = new TestCaseGroup(m_context, "8_attributes", "Test draw call batching with 8 attributes.");
|
|
|
|
callCountGroup->addChild(attributeCount1Group);
|
|
callCountGroup->addChild(attributeCount8Group);
|
|
|
|
drawTypeGroup->addChild(callCountGroup);
|
|
|
|
for (int attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(dynamicAttributeCounts); attributeCountNdx++)
|
|
{
|
|
TestCaseGroup* attributeCountGroup = NULL;
|
|
|
|
int staticAttributeCount = staticAttributeCounts[attributeCountNdx];
|
|
int dynamicAttributeCount = dynamicAttributeCounts[attributeCountNdx];
|
|
|
|
if (staticAttributeCount + dynamicAttributeCount == 1)
|
|
attributeCountGroup = attributeCount1Group;
|
|
else if (staticAttributeCount + dynamicAttributeCount == 8)
|
|
attributeCountGroup = attributeCount8Group;
|
|
else
|
|
DE_ASSERT(false);
|
|
|
|
for (int triangleCountNdx = 0; triangleCountNdx < DE_LENGTH_OF_ARRAY(triangleCounts); triangleCountNdx++)
|
|
{
|
|
int triangleCount = triangleCounts[triangleCountNdx];
|
|
|
|
for (int dynamicBufferNdx = 0; dynamicBufferNdx < 2; dynamicBufferNdx++)
|
|
{
|
|
bool useDynamicBuffer = (dynamicBufferNdx != 0);
|
|
|
|
for (int staticBufferNdx = 0; staticBufferNdx < 2; staticBufferNdx++)
|
|
{
|
|
bool useStaticBuffer = (staticBufferNdx != 0);
|
|
|
|
DrawCallBatchingTest::TestSpec spec;
|
|
|
|
spec.useStaticBuffer = useStaticBuffer;
|
|
spec.staticAttributeCount = staticAttributeCount;
|
|
|
|
spec.useDynamicBuffer = useDynamicBuffer;
|
|
spec.dynamicAttributeCount = dynamicAttributeCount;
|
|
|
|
spec.drawCallCount = drawCallCount;
|
|
spec.triangleCount = triangleCount;
|
|
|
|
spec.useDrawElements = drawElements;
|
|
spec.useIndexBuffer = useIndexBuffer;
|
|
spec.dynamicIndices = dynamicIndices;
|
|
|
|
if (spec.useStaticBuffer && spec.staticAttributeCount == 0)
|
|
continue;
|
|
|
|
if (spec.useDynamicBuffer && spec.dynamicAttributeCount == 0)
|
|
continue;
|
|
|
|
attributeCountGroup->addChild(new DrawCallBatchingTest(m_context, specToName(spec).c_str(), specToDescrpition(spec).c_str(), spec));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // Performance
|
|
} // gles2
|
|
} // deqp
|