зеркало из https://github.com/AvaloniaUI/angle.git
Add an instancing perf test.
BUG=526217 BUG=angleproject:1164 Change-Id: Ia353a3b2fa0ab0e8b7fd15d72bb63e5ecb7833b1 Reviewed-on: https://chromium-review.googlesource.com/301469 Reviewed-by: Geoff Lang <geofflang@chromium.org> Tryjob-Request: Jamie Madill <jmadill@chromium.org> Tested-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Родитель
3215b207b2
Коммит
90c253a616
|
@ -14,6 +14,8 @@
|
|||
#include "random_utils.h"
|
||||
#include "shader_utils.h"
|
||||
|
||||
using namespace angle;
|
||||
|
||||
class MultiWindowSample : public SampleApplication
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
using namespace angle;
|
||||
|
||||
class ParticleSystemSample : public SampleApplication
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "SampleApplication.h"
|
||||
#include "EGLWindow.h"
|
||||
#include "random_utils.h"
|
||||
|
||||
SampleApplication::SampleApplication(const std::string &name,
|
||||
size_t width,
|
||||
|
@ -29,6 +30,8 @@ SampleApplication::SampleApplication(const std::string &name,
|
|||
|
||||
// Disable vsync
|
||||
mEGLWindow->setSwapInterval(0);
|
||||
|
||||
angle::RandomInitFromTime();
|
||||
}
|
||||
|
||||
SampleApplication::~SampleApplication()
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
'<(angle_path)/src/tests/perf_tests/DrawCallPerf.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/EGLInitializePerf.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/IndexConversionPerf.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/InstancingPerf.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/InterleavedAttributeData.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/PointSprites.cpp',
|
||||
'<(angle_path)/src/tests/perf_tests/TexSubImage.cpp',
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
//
|
||||
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// InstancingPerf:
|
||||
// Performance tests for ANGLE instanced draw calls.
|
||||
//
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "ANGLEPerfTest.h"
|
||||
#include "Matrix.h"
|
||||
#include "random_utils.h"
|
||||
#include "shader_utils.h"
|
||||
#include "Vector.h"
|
||||
|
||||
using namespace angle;
|
||||
using namespace egl_platform;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
float AnimationSignal(float t)
|
||||
{
|
||||
float l = t / 2.0f;
|
||||
float f = l - floor(l);
|
||||
return (f > 0.5f ? 1.0f - f : f) * 4.0f - 1.0f;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t VectorSizeBytes(const std::vector<T> &vec)
|
||||
{
|
||||
return sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
struct InstancingPerfParams final : public RenderTestParams
|
||||
{
|
||||
// Common default options
|
||||
InstancingPerfParams()
|
||||
{
|
||||
majorVersion = 2;
|
||||
minorVersion = 0;
|
||||
windowWidth = 256;
|
||||
windowHeight = 256;
|
||||
iterations = 1;
|
||||
runTimeSeconds = 10.0;
|
||||
animationEnabled = false;
|
||||
instancingEnabled = true;
|
||||
}
|
||||
|
||||
std::string suffix() const override
|
||||
{
|
||||
std::stringstream strstr;
|
||||
|
||||
strstr << RenderTestParams::suffix();
|
||||
|
||||
if (!instancingEnabled)
|
||||
{
|
||||
strstr << "_billboards";
|
||||
}
|
||||
|
||||
return strstr.str();
|
||||
}
|
||||
|
||||
unsigned int iterations;
|
||||
double runTimeSeconds;
|
||||
bool animationEnabled;
|
||||
bool instancingEnabled;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const InstancingPerfParams ¶ms)
|
||||
{
|
||||
os << params.suffix().substr(1);
|
||||
return os;
|
||||
}
|
||||
|
||||
class InstancingPerfBenchmark : public ANGLERenderTest,
|
||||
public ::testing::WithParamInterface<InstancingPerfParams>
|
||||
{
|
||||
public:
|
||||
InstancingPerfBenchmark();
|
||||
|
||||
void initializeBenchmark() override;
|
||||
void destroyBenchmark() override;
|
||||
void beginDrawBenchmark() override;
|
||||
void drawBenchmark() override;
|
||||
|
||||
private:
|
||||
GLuint mProgram;
|
||||
std::vector<GLuint> mBuffers;
|
||||
GLuint mNumPoints;
|
||||
std::vector<Vector3> mTranslateData;
|
||||
std::vector<float> mSizeData;
|
||||
std::vector<Vector3> mColorData;
|
||||
};
|
||||
|
||||
InstancingPerfBenchmark::InstancingPerfBenchmark()
|
||||
: ANGLERenderTest("InstancingPerf", GetParam()), mProgram(0), mNumPoints(75000)
|
||||
{
|
||||
mRunTimeSeconds = GetParam().runTimeSeconds;
|
||||
}
|
||||
|
||||
void InstancingPerfBenchmark::initializeBenchmark()
|
||||
{
|
||||
const auto ¶ms = GetParam();
|
||||
|
||||
ASSERT_TRUE(params.iterations > 0);
|
||||
mDrawIterations = params.iterations;
|
||||
|
||||
const std::string vs =
|
||||
"attribute vec2 aPosition;\n"
|
||||
"attribute vec3 aTranslate;\n"
|
||||
"attribute float aScale;\n"
|
||||
"attribute vec3 aColor;\n"
|
||||
"uniform mat4 uWorldMatrix;\n"
|
||||
"uniform mat4 uProjectionMatrix;\n"
|
||||
"varying vec3 vColor;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 position = uWorldMatrix * vec4(aTranslate, 1.0);\n"
|
||||
" position.xy += aPosition * aScale;\n"
|
||||
" gl_Position = uProjectionMatrix * position;\n"
|
||||
" vColor = aColor;\n"
|
||||
"}\n";
|
||||
|
||||
const std::string fs =
|
||||
"precision mediump float;\n"
|
||||
"varying vec3 vColor;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = vec4(vColor, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
mProgram = CompileProgram(vs, fs);
|
||||
ASSERT_TRUE(mProgram != 0);
|
||||
|
||||
glUseProgram(mProgram);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
GLuint baseIndexData[6] = {0, 1, 2, 1, 3, 2};
|
||||
Vector2 basePositionData[4] = {Vector2(-1.0f, 1.0f), Vector2(1.0f, 1.0f), Vector2(-1.0f, -1.0f),
|
||||
Vector2(1.0f, -1.0f)};
|
||||
|
||||
std::vector<GLuint> indexData;
|
||||
std::vector<Vector2> positionData;
|
||||
|
||||
if (!params.instancingEnabled)
|
||||
{
|
||||
GLuint pointVertexStride = 4;
|
||||
for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
|
||||
{
|
||||
for (GLuint indexIndex = 0; indexIndex < 6; ++indexIndex)
|
||||
{
|
||||
indexData.push_back(baseIndexData[indexIndex] + pointIndex * pointVertexStride);
|
||||
}
|
||||
|
||||
Vector3 randVec(RandomNegativeOneToOne(), RandomNegativeOneToOne(),
|
||||
RandomNegativeOneToOne());
|
||||
for (GLuint vertexIndex = 0; vertexIndex < 4; ++vertexIndex)
|
||||
{
|
||||
positionData.push_back(basePositionData[vertexIndex]);
|
||||
mTranslateData.push_back(randVec);
|
||||
}
|
||||
}
|
||||
|
||||
mSizeData.resize(mNumPoints * 4, 0.012f);
|
||||
mColorData.resize(mNumPoints * 4, Vector3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (GLuint index : baseIndexData)
|
||||
{
|
||||
indexData.push_back(index);
|
||||
}
|
||||
|
||||
for (const Vector2 &position : basePositionData)
|
||||
{
|
||||
positionData.push_back(position);
|
||||
}
|
||||
|
||||
for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
|
||||
{
|
||||
Vector3 randVec(RandomNegativeOneToOne(), RandomNegativeOneToOne(),
|
||||
RandomNegativeOneToOne());
|
||||
mTranslateData.push_back(randVec);
|
||||
}
|
||||
|
||||
mSizeData.resize(mNumPoints, 0.012f);
|
||||
mColorData.resize(mNumPoints, Vector3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
mBuffers.resize(5, 0);
|
||||
glGenBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
|
||||
|
||||
// Index Data
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffers[0]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, VectorSizeBytes(indexData), &indexData[0],
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
// Position Data
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(positionData), &positionData[0], GL_STATIC_DRAW);
|
||||
GLint positionLocation = glGetAttribLocation(mProgram, "aPosition");
|
||||
ASSERT_NE(-1, positionLocation);
|
||||
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
|
||||
glEnableVertexAttribArray(positionLocation);
|
||||
|
||||
// Translate Data
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mTranslateData), &mTranslateData[0],
|
||||
GL_STATIC_DRAW);
|
||||
GLint translateLocation = glGetAttribLocation(mProgram, "aTranslate");
|
||||
ASSERT_NE(-1, translateLocation);
|
||||
glVertexAttribPointer(translateLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
|
||||
glEnableVertexAttribArray(translateLocation);
|
||||
glVertexAttribDivisorANGLE(translateLocation, 1);
|
||||
|
||||
// Scale Data
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
|
||||
glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mSizeData), nullptr, GL_DYNAMIC_DRAW);
|
||||
GLint scaleLocation = glGetAttribLocation(mProgram, "aScale");
|
||||
ASSERT_NE(-1, scaleLocation);
|
||||
glVertexAttribPointer(scaleLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
|
||||
glEnableVertexAttribArray(scaleLocation);
|
||||
glVertexAttribDivisorANGLE(scaleLocation, 1);
|
||||
|
||||
// Color Data
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
|
||||
glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mColorData), nullptr, GL_DYNAMIC_DRAW);
|
||||
GLint colorLocation = glGetAttribLocation(mProgram, "aColor");
|
||||
ASSERT_NE(-1, colorLocation);
|
||||
glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
|
||||
glEnableVertexAttribArray(colorLocation);
|
||||
glVertexAttribDivisorANGLE(colorLocation, 1);
|
||||
|
||||
// Set the viewport
|
||||
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
|
||||
|
||||
// Init matrices
|
||||
GLint worldMatrixLocation = glGetUniformLocation(mProgram, "uWorldMatrix");
|
||||
ASSERT_NE(-1, worldMatrixLocation);
|
||||
Matrix4 worldMatrix = Matrix4::translate(Vector3(0, 0, -3.0f));
|
||||
worldMatrix *= Matrix4::rotate(25.0f, Vector3(0.6f, 1.0f, 0.0f));
|
||||
glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, &worldMatrix.data[0]);
|
||||
|
||||
GLint projectionMatrixLocation = glGetUniformLocation(mProgram, "uProjectionMatrix");
|
||||
ASSERT_NE(-1, projectionMatrixLocation);
|
||||
float fov =
|
||||
static_cast<float>(getWindow()->getWidth()) / static_cast<float>(getWindow()->getHeight());
|
||||
Matrix4 projectionMatrix = Matrix4::perspective(60.0f, fov, 1.0f, 300.0f);
|
||||
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix.data[0]);
|
||||
|
||||
getWindow()->setVisible(true);
|
||||
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
void InstancingPerfBenchmark::destroyBenchmark()
|
||||
{
|
||||
glDeleteProgram(mProgram);
|
||||
|
||||
if (!mBuffers.empty())
|
||||
{
|
||||
glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
|
||||
mBuffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void InstancingPerfBenchmark::beginDrawBenchmark()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void InstancingPerfBenchmark::drawBenchmark()
|
||||
{
|
||||
const auto ¶ms = GetParam();
|
||||
|
||||
// Animatino makes the test more interesting visually, but also eats up many CPU cycles.
|
||||
if (params.animationEnabled)
|
||||
{
|
||||
// Not implemented for billboards.
|
||||
ASSERT(params.instancingEnabled);
|
||||
|
||||
float time = static_cast<float>(mTimer->getElapsedTime());
|
||||
|
||||
for (size_t pointIndex = 0; pointIndex < mTranslateData.size(); ++pointIndex)
|
||||
{
|
||||
const Vector3 &translate = mTranslateData[pointIndex];
|
||||
|
||||
float tx = translate.x + time;
|
||||
float ty = translate.y + time;
|
||||
float tz = translate.z + time;
|
||||
|
||||
float scale = AnimationSignal(tx) * 0.01f + 0.01f;
|
||||
mSizeData[pointIndex] = scale;
|
||||
|
||||
Vector3 color;
|
||||
color.x = AnimationSignal(tx) * 0.5f + 0.5f;
|
||||
color.y = AnimationSignal(ty) * 0.5f + 0.5f;
|
||||
color.z = AnimationSignal(tz) * 0.5f + 0.5f;
|
||||
|
||||
mColorData[pointIndex] = color;
|
||||
}
|
||||
}
|
||||
|
||||
// Update scales and colors.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mSizeData), &mSizeData[0]);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mColorData), &mColorData[0]);
|
||||
|
||||
// Render the instances/billboards.
|
||||
if (params.instancingEnabled)
|
||||
{
|
||||
for (unsigned int it = 0; it < params.iterations; it++)
|
||||
{
|
||||
glDrawElementsInstancedANGLE(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, mNumPoints);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int it = 0; it < params.iterations; it++)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLES, 6 * mNumPoints, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
InstancingPerfParams InstancingPerfD3D11Params()
|
||||
{
|
||||
InstancingPerfParams params;
|
||||
params.eglParameters = D3D11();
|
||||
return params;
|
||||
}
|
||||
|
||||
InstancingPerfParams InstancingPerfD3D9Params()
|
||||
{
|
||||
InstancingPerfParams params;
|
||||
params.eglParameters = D3D9();
|
||||
return params;
|
||||
}
|
||||
|
||||
InstancingPerfParams InstancingPerfOpenGLParams()
|
||||
{
|
||||
InstancingPerfParams params;
|
||||
params.eglParameters = OPENGL();
|
||||
return params;
|
||||
}
|
||||
|
||||
TEST_P(InstancingPerfBenchmark, Run)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
ANGLE_INSTANTIATE_TEST(InstancingPerfBenchmark,
|
||||
InstancingPerfD3D11Params(),
|
||||
InstancingPerfD3D9Params(),
|
||||
InstancingPerfOpenGLParams());
|
||||
|
||||
} // anonymous namespace
|
|
@ -3,20 +3,35 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// random_utils:
|
||||
// Helper functions for random number generation.
|
||||
//
|
||||
|
||||
#include "random_utils.h"
|
||||
#include <time.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace angle
|
||||
{
|
||||
|
||||
void RandomInitFromTime()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)));
|
||||
}
|
||||
|
||||
float RandomFloat()
|
||||
{
|
||||
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
|
||||
}
|
||||
|
||||
float RandomBetween(float min, float max)
|
||||
{
|
||||
static bool randInitialized = false;
|
||||
if (!randInitialized)
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)));
|
||||
randInitialized = true;
|
||||
}
|
||||
|
||||
const size_t divisor = 10000;
|
||||
return min + ((rand() % divisor) / static_cast<float>(divisor)) * (max - min);
|
||||
return min + RandomFloat() * (max - min);
|
||||
}
|
||||
|
||||
float RandomNegativeOneToOne()
|
||||
{
|
||||
return RandomBetween(0.0f, 1.0f);
|
||||
}
|
||||
|
||||
} // namespace angle
|
||||
|
|
|
@ -3,10 +3,22 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// random_utils:
|
||||
// Helper functions for random number generation.
|
||||
//
|
||||
|
||||
#ifndef UTIL_RANDOM_UTILS_H
|
||||
#define UTIL_RANDOM_UTILS_H
|
||||
|
||||
namespace angle
|
||||
{
|
||||
|
||||
// TODO(jmadill): Should make this a class
|
||||
void RandomInitFromTime();
|
||||
float RandomFloat();
|
||||
float RandomBetween(float min, float max);
|
||||
float RandomNegativeOneToOne();
|
||||
|
||||
} // namespace angle
|
||||
|
||||
#endif // UTIL_RANDOM_UTILS_H
|
||||
|
|
|
@ -46,10 +46,16 @@ GLuint CompileShader(GLenum type, const std::string &source)
|
|||
GLint infoLogLength;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
std::vector<GLchar> infoLog(infoLogLength);
|
||||
glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), NULL, &infoLog[0]);
|
||||
|
||||
std::cerr << "shader compilation failed: " << &infoLog[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "shader compilation failed. <Empty log message>";
|
||||
}
|
||||
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче