diff options
Diffstat (limited to 'gfx/angle/src/tests/perf_tests')
18 files changed, 4132 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.cpp b/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.cpp new file mode 100755 index 000000000..e7c74370d --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.cpp @@ -0,0 +1,194 @@ +// +// Copyright (c) 2014 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. +// +// ANGLEPerfTests: +// Base class for google test performance tests +// + +#include "ANGLEPerfTest.h" + +#include "third_party/perf/perf_test.h" + +#include <cassert> +#include <cmath> +#include <iostream> + +ANGLEPerfTest::ANGLEPerfTest(const std::string &name, const std::string &suffix) + : mName(name), + mSuffix(suffix), + mTimer(nullptr), + mRunTimeSeconds(5.0), + mNumStepsPerformed(0), + mRunning(true) +{ + mTimer = CreateTimer(); +} + +ANGLEPerfTest::~ANGLEPerfTest() +{ + SafeDelete(mTimer); +} + +void ANGLEPerfTest::run() +{ + mTimer->start(); + while (mRunning) + { + step(); + if (mRunning) + { + ++mNumStepsPerformed; + } + if (mTimer->getElapsedTime() > mRunTimeSeconds) + { + mRunning = false; + } + } + finishTest(); + mTimer->stop(); +} + +void ANGLEPerfTest::printResult(const std::string &trace, double value, const std::string &units, bool important) const +{ + perf_test::PrintResult(mName, mSuffix, trace, value, units, important); +} + +void ANGLEPerfTest::printResult(const std::string &trace, size_t value, const std::string &units, bool important) const +{ + perf_test::PrintResult(mName, mSuffix, trace, value, units, important); +} + +void ANGLEPerfTest::SetUp() +{ +} + +void ANGLEPerfTest::TearDown() +{ + double relativeScore = static_cast<double>(mNumStepsPerformed) / mTimer->getElapsedTime(); + printResult("score", static_cast<size_t>(std::round(relativeScore)), "score", true); +} + +double ANGLEPerfTest::normalizedTime(size_t value) const +{ + return static_cast<double>(value) / static_cast<double>(mNumStepsPerformed); +} + +std::string RenderTestParams::suffix() const +{ + switch (getRenderer()) + { + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + return "_d3d11"; + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + return "_d3d9"; + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + return "_gl"; + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + return "_gles"; + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + return "_default"; + default: + assert(0); + return "_unk"; + } +} + +ANGLERenderTest::ANGLERenderTest(const std::string &name, const RenderTestParams &testParams) + : ANGLEPerfTest(name, testParams.suffix()), + mTestParams(testParams), + mEGLWindow(nullptr), + mOSWindow(nullptr) +{ +} + +ANGLERenderTest::~ANGLERenderTest() +{ + SafeDelete(mOSWindow); + SafeDelete(mEGLWindow); +} + +void ANGLERenderTest::SetUp() +{ + mOSWindow = CreateOSWindow(); + mEGLWindow = new EGLWindow(mTestParams.majorVersion, mTestParams.minorVersion, + mTestParams.eglParameters); + mEGLWindow->setSwapInterval(0); + + if (!mOSWindow->initialize(mName, mTestParams.windowWidth, mTestParams.windowHeight)) + { + FAIL() << "Failed initializing OSWindow"; + return; + } + + if (!mEGLWindow->initializeGL(mOSWindow)) + { + FAIL() << "Failed initializing EGLWindow"; + return; + } + + initializeBenchmark(); + + ANGLEPerfTest::SetUp(); +} + +void ANGLERenderTest::TearDown() +{ + ANGLEPerfTest::TearDown(); + + destroyBenchmark(); + + mEGLWindow->destroyGL(); + mOSWindow->destroy(); +} + +void ANGLERenderTest::step() +{ + // Clear events that the application did not process from this frame + Event event; + bool closed = false; + while (popEvent(&event)) + { + // If the application did not catch a close event, close now + if (event.Type == Event::EVENT_CLOSED) + { + closed = true; + } + } + + if (closed) + { + abortTest(); + } + else + { + drawBenchmark(); + // Swap is needed so that the GPU driver will occasionally flush its internal command queue + // to the GPU. The null device benchmarks are only testing CPU overhead, so they don't need + // to swap. + if (mTestParams.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) + { + mEGLWindow->swap(); + } + mOSWindow->messageLoop(); + } +} + +void ANGLERenderTest::finishTest() +{ + if (mTestParams.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) + { + glFinish(); + } +} + +bool ANGLERenderTest::popEvent(Event *event) +{ + return mOSWindow->popEvent(event); +} + +OSWindow *ANGLERenderTest::getWindow() +{ + return mOSWindow; +} diff --git a/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.h b/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.h new file mode 100755 index 000000000..62f2cb444 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/ANGLEPerfTest.h @@ -0,0 +1,107 @@ +// +// Copyright (c) 2014 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. +// +// ANGLEPerfTests: +// Base class for google test performance tests +// + +#ifndef PERF_TESTS_ANGLE_PERF_TEST_H_ +#define PERF_TESTS_ANGLE_PERF_TEST_H_ + +#include <string> +#include <vector> + +#include <gtest/gtest.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "common/angleutils.h" +#include "common/debug.h" +#include "EGLWindow.h" +#include "OSWindow.h" +#include "test_utils/angle_test_configs.h" +#include "test_utils/angle_test_instantiate.h" +#include "Timer.h" + +class Event; + +#ifndef ASSERT_GL_NO_ERROR +#define ASSERT_GL_NO_ERROR() ASSERT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()) +#endif + +class ANGLEPerfTest : public testing::Test, angle::NonCopyable +{ + public: + ANGLEPerfTest(const std::string &name, const std::string &suffix); + virtual ~ANGLEPerfTest(); + + virtual void step() = 0; + + // Called right before timer is stopped to let the test wait for asynchronous operations. + virtual void finishTest() {} + + protected: + void run(); + void printResult(const std::string &trace, double value, const std::string &units, bool important) const; + void printResult(const std::string &trace, size_t value, const std::string &units, bool important) const; + void SetUp() override; + void TearDown() override; + + // Normalize a time value according to the number of test loop iterations (mFrameCount) + double normalizedTime(size_t value) const; + + // Call if the test step was aborted and the test should stop running. + void abortTest() { mRunning = false; } + + unsigned int getNumStepsPerformed() const { return mNumStepsPerformed; } + + std::string mName; + std::string mSuffix; + Timer *mTimer; + double mRunTimeSeconds; + + private: + unsigned int mNumStepsPerformed; + bool mRunning; +}; + +struct RenderTestParams : public angle::PlatformParameters +{ + virtual std::string suffix() const; + + EGLint windowWidth; + EGLint windowHeight; +}; + +class ANGLERenderTest : public ANGLEPerfTest +{ + public: + ANGLERenderTest(const std::string &name, const RenderTestParams &testParams); + ~ANGLERenderTest(); + + virtual void initializeBenchmark() { } + virtual void destroyBenchmark() { } + + virtual void drawBenchmark() = 0; + + bool popEvent(Event *event); + + OSWindow *getWindow(); + + protected: + const RenderTestParams &mTestParams; + + private: + void SetUp() override; + void TearDown() override; + + void step() override; + void finishTest() override; + + EGLWindow *mEGLWindow; + OSWindow *mOSWindow; +}; + +#endif // PERF_TESTS_ANGLE_PERF_TEST_H_ diff --git a/gfx/angle/src/tests/perf_tests/BufferSubData.cpp b/gfx/angle/src/tests/perf_tests/BufferSubData.cpp new file mode 100755 index 000000000..5818d52ee --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/BufferSubData.cpp @@ -0,0 +1,418 @@ +// +// Copyright (c) 2014 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. +// +// BufferSubDataBenchmark: +// Performance test for ANGLE buffer updates. +// + +#include <sstream> + +#include "ANGLEPerfTest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct BufferSubDataParams final : public RenderTestParams +{ + BufferSubDataParams() + { + // Common default values + majorVersion = 2; + minorVersion = 0; + windowWidth = 512; + windowHeight = 512; + updateSize = 3000; + bufferSize = 40000000; + iterations = 4; + updateRate = 1; + } + + std::string suffix() const override; + + GLboolean vertexNormalized; + GLenum vertexType; + GLint vertexComponentCount; + unsigned int updateRate; + + // static parameters + GLsizeiptr updateSize; + GLsizeiptr bufferSize; + unsigned int iterations; +}; + +std::ostream &operator<<(std::ostream &os, const BufferSubDataParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +class BufferSubDataBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<BufferSubDataParams> +{ + public: + BufferSubDataBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint mProgram; + GLuint mBuffer; + uint8_t *mUpdateData; + int mNumTris; +}; + +GLfloat *GetFloatData(GLint componentCount) +{ + static GLfloat vertices2[] = + { + 1, 2, + 0, 0, + 2, 0, + }; + + static GLfloat vertices3[] = + { + 1, 2, 1, + 0, 0, 1, + 2, 0, 1, + }; + + static GLfloat vertices4[] = + { + 1, 2, 1, 3, + 0, 0, 1, 3, + 2, 0, 1, 3, + }; + + switch (componentCount) + { + case 2: + return vertices2; + case 3: + return vertices3; + case 4: + return vertices4; + default: + return nullptr; + } +} + +template <class T> +GLsizeiptr GetNormalizedData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data) +{ + GLsizeiptr triDataSize = sizeof(T) * numElements; + data->resize(triDataSize); + + T *destPtr = reinterpret_cast<T*>(data->data()); + + for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++) + { + GLfloat scaled = floatData[dataIndex] * 0.25f; + destPtr[dataIndex] = static_cast<T>(scaled * static_cast<GLfloat>(std::numeric_limits<T>::max())); + } + + return triDataSize; +} + +template <class T> +GLsizeiptr GetIntData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data) +{ + GLsizeiptr triDataSize = sizeof(T) * numElements; + data->resize(triDataSize); + + T *destPtr = reinterpret_cast<T*>(data->data()); + + for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++) + { + destPtr[dataIndex] = static_cast<T>(floatData[dataIndex]); + } + + return triDataSize; +} + +GLsizeiptr GetVertexData(GLenum type, GLint componentCount, GLboolean normalized, std::vector<uint8_t> *data) +{ + GLsizeiptr triDataSize = 0; + GLfloat *floatData = GetFloatData(componentCount); + + if (type == GL_FLOAT) + { + triDataSize = sizeof(GLfloat) * componentCount * 3; + data->resize(triDataSize); + memcpy(data->data(), floatData, triDataSize); + } + else if (normalized == GL_TRUE) + { + GLsizeiptr numElements = componentCount * 3; + + switch (type) + { + case GL_BYTE: + triDataSize = GetNormalizedData<GLbyte>(numElements, floatData, data); + break; + case GL_SHORT: + triDataSize = GetNormalizedData<GLshort>(numElements, floatData, data); + break; + case GL_INT: + triDataSize = GetNormalizedData<GLint>(numElements, floatData, data); + break; + case GL_UNSIGNED_BYTE: + triDataSize = GetNormalizedData<GLubyte>(numElements, floatData, data); + break; + case GL_UNSIGNED_SHORT: + triDataSize = GetNormalizedData<GLushort>(numElements, floatData, data); + break; + case GL_UNSIGNED_INT: + triDataSize = GetNormalizedData<GLuint>(numElements, floatData, data); + break; + default: + assert(0); + } + } + else + { + GLsizeiptr numElements = componentCount * 3; + + switch (type) + { + case GL_BYTE: + triDataSize = GetIntData<GLbyte>(numElements, floatData, data); + break; + case GL_SHORT: + triDataSize = GetIntData<GLshort>(numElements, floatData, data); + break; + case GL_INT: + triDataSize = GetIntData<GLint>(numElements, floatData, data); + break; + case GL_UNSIGNED_BYTE: + triDataSize = GetIntData<GLubyte>(numElements, floatData, data); + break; + case GL_UNSIGNED_SHORT: + triDataSize = GetIntData<GLushort>(numElements, floatData, data); + break; + case GL_UNSIGNED_INT: + triDataSize = GetIntData<GLuint>(numElements, floatData, data); + break; + default: + assert(0); + } + } + + return triDataSize; +} + +std::string BufferSubDataParams::suffix() const +{ + std::stringstream strstr; + + strstr << RenderTestParams::suffix(); + + if (vertexNormalized) + { + strstr << "_norm"; + } + + switch (vertexType) + { + case GL_FLOAT: + strstr << "_float"; + break; + case GL_INT: + strstr << "_int"; + break; + case GL_BYTE: + strstr << "_byte"; + break; + case GL_SHORT: + strstr << "_short"; + break; + case GL_UNSIGNED_INT: + strstr << "_uint"; + break; + case GL_UNSIGNED_BYTE: + strstr << "_ubyte"; + break; + case GL_UNSIGNED_SHORT: + strstr << "_ushort"; + break; + default: + strstr << "_vunk_" << vertexType << "_"; + break; + } + + strstr << vertexComponentCount; + strstr << "_every" << updateRate; + + return strstr.str(); +} + +BufferSubDataBenchmark::BufferSubDataBenchmark() + : ANGLERenderTest("BufferSubData", GetParam()), + mProgram(0), + mBuffer(0), + mUpdateData(nullptr), + mNumTris(0) +{ +} + +void BufferSubDataBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(1, params.vertexComponentCount); + ASSERT_LT(0u, params.iterations); + + const std::string vs = SHADER_SOURCE + ( + attribute vec2 vPosition; + uniform float uScale; + uniform float uOffset; + void main() + { + gl_Position = vec4(vPosition * vec2(uScale) - vec2(uOffset), 0, 1); + } + ); + + const std::string fs = SHADER_SOURCE + ( + precision mediump float; + void main() + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + ); + + mProgram = CompileProgram(vs, fs); + ASSERT_NE(0u, mProgram); + + // Use the program object + glUseProgram(mProgram); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + + std::vector<uint8_t> zeroData(params.bufferSize); + memset(&zeroData[0], 0, zeroData.size()); + + glGenBuffers(1, &mBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + glBufferData(GL_ARRAY_BUFFER, params.bufferSize, &zeroData[0], GL_DYNAMIC_DRAW); + + glVertexAttribPointer(0, params.vertexComponentCount, params.vertexType, + params.vertexNormalized, 0, 0); + glEnableVertexAttribArray(0); + + if (params.updateSize > 0) + { + mUpdateData = new uint8_t[params.updateSize]; + } + + std::vector<uint8_t> data; + GLsizei triDataSize = static_cast<GLsizei>(GetVertexData(params.vertexType, + params.vertexComponentCount, + params.vertexNormalized, &data)); + + mNumTris = static_cast<int>(params.updateSize / triDataSize); + for (int i = 0, offset = 0; i < mNumTris; ++i) + { + memcpy(mUpdateData + offset, &data[0], triDataSize); + offset += triDataSize; + } + + if (params.updateSize == 0) + { + mNumTris = 1; + glBufferSubData(GL_ARRAY_BUFFER, 0, data.size(), &data[0]); + } + + // Set the viewport + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + GLfloat scale = 0.5f; + GLfloat offset = 0.5f; + + if (params.vertexNormalized == GL_TRUE) + { + scale = 2.0f; + offset = 0.5f; + } + + glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale); + glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset); + + ASSERT_GL_NO_ERROR(); +} + +void BufferSubDataBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mBuffer); + SafeDeleteArray(mUpdateData); +} + +void BufferSubDataBenchmark::drawBenchmark() +{ + glClear(GL_COLOR_BUFFER_BIT); + + const auto ¶ms = GetParam(); + + for (unsigned int it = 0; it < params.iterations; it++) + { + if (params.updateSize > 0 && ((getNumStepsPerformed() % params.updateRate) == 0)) + { + glBufferSubData(GL_ARRAY_BUFFER, 0, params.updateSize, mUpdateData); + } + + glDrawArrays(GL_TRIANGLES, 0, 3 * mNumTris); + } + + ASSERT_GL_NO_ERROR(); +} + +BufferSubDataParams BufferUpdateD3D11Params() +{ + BufferSubDataParams params; + params.eglParameters = egl_platform::D3D11(); + params.vertexType = GL_FLOAT; + params.vertexComponentCount = 4; + params.vertexNormalized = GL_FALSE; + return params; +} + +BufferSubDataParams BufferUpdateD3D9Params() +{ + BufferSubDataParams params; + params.eglParameters = egl_platform::D3D9(); + params.vertexType = GL_FLOAT; + params.vertexComponentCount = 4; + params.vertexNormalized = GL_FALSE; + return params; +} + +BufferSubDataParams BufferUpdateOpenGLParams() +{ + BufferSubDataParams params; + params.eglParameters = egl_platform::OPENGL(); + params.vertexType = GL_FLOAT; + params.vertexComponentCount = 4; + params.vertexNormalized = GL_FALSE; + return params; +} + +TEST_P(BufferSubDataBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(BufferSubDataBenchmark, + BufferUpdateD3D11Params(), BufferUpdateD3D9Params(), + BufferUpdateOpenGLParams()); + +} // namespace diff --git a/gfx/angle/src/tests/perf_tests/DrawCallPerf.cpp b/gfx/angle/src/tests/perf_tests/DrawCallPerf.cpp new file mode 100755 index 000000000..e5007e19e --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/DrawCallPerf.cpp @@ -0,0 +1,256 @@ +// +// Copyright (c) 2014 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. +// +// DrawCallPerf: +// Performance tests for ANGLE draw call overhead. +// + +#include <sstream> + +#include "ANGLEPerfTest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct DrawCallPerfParams final : public RenderTestParams +{ + // Common default options + DrawCallPerfParams() + { + majorVersion = 2; + minorVersion = 0; + windowWidth = 256; + windowHeight = 256; + } + + std::string suffix() const override + { + std::stringstream strstr; + + strstr << RenderTestParams::suffix(); + + if (numTris == 0) + { + strstr << "_validation_only"; + } + + if (useFBO) + { + strstr << "_render_to_texture"; + } + + if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) + { + strstr << "_null"; + } + + return strstr.str(); + } + + unsigned int iterations = 50; + double runTimeSeconds = 10.0; + int numTris = 1; + bool useFBO = false; +}; + +std::ostream &operator<<(std::ostream &os, const DrawCallPerfParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +class DrawCallPerfBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<DrawCallPerfParams> +{ + public: + DrawCallPerfBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint mProgram = 0; + GLuint mBuffer = 0; + GLuint mFBO = 0; + GLuint mTexture = 0; + int mNumTris = GetParam().numTris; +}; + +DrawCallPerfBenchmark::DrawCallPerfBenchmark() : ANGLERenderTest("DrawCallPerf", GetParam()) +{ + mRunTimeSeconds = GetParam().runTimeSeconds; +} + +void DrawCallPerfBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(0u, params.iterations); + + const std::string vs = SHADER_SOURCE + ( + attribute vec2 vPosition; + uniform float uScale; + uniform float uOffset; + void main() + { + gl_Position = vec4(vPosition * vec2(uScale) - vec2(uOffset), 0, 1); + } + ); + + const std::string fs = SHADER_SOURCE + ( + precision mediump float; + void main() + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + ); + + mProgram = CompileProgram(vs, fs); + ASSERT_NE(0u, mProgram); + + // Use the program object + glUseProgram(mProgram); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + std::vector<GLfloat> floatData; + + for (int quadIndex = 0; quadIndex < mNumTris; ++quadIndex) + { + floatData.push_back(1); + floatData.push_back(2); + floatData.push_back(0); + floatData.push_back(0); + floatData.push_back(2); + floatData.push_back(0); + } + + glGenBuffers(1, &mBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + + // To avoid generating GL errors when testing validation-only + if (floatData.empty()) + { + floatData.push_back(0.0f); + } + + glBufferData(GL_ARRAY_BUFFER, floatData.size() * sizeof(GLfloat), &floatData[0], GL_STATIC_DRAW); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + // Set the viewport + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + GLfloat scale = 0.5f; + GLfloat offset = 0.5f; + + glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale); + glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset); + + if (params.useFBO) + { + glGenFramebuffers(1, &mFBO); + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glGenTextures(1, &mTexture); + glBindTexture(GL_TEXTURE_2D, mTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindow()->getWidth(), getWindow()->getHeight(), + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0); + } + + ASSERT_GL_NO_ERROR(); +} + +void DrawCallPerfBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mBuffer); + glDeleteTextures(1, &mTexture); + glDeleteFramebuffers(1, &mFBO); +} + +void DrawCallPerfBenchmark::drawBenchmark() +{ + // This workaround fixes a huge queue of graphics commands accumulating on the GL + // back-end. The GL back-end doesn't have a proper NULL device at the moment. + // TODO(jmadill): Remove this when/if we ever get a proper OpenGL NULL device. + const auto &eglParams = GetParam().eglParameters; + if (eglParams.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE || + (eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE && + eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) + { + glClear(GL_COLOR_BUFFER_BIT); + } + + const auto ¶ms = GetParam(); + + for (unsigned int it = 0; it < params.iterations; it++) + { + glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(3 * mNumTris)); + } + + ASSERT_GL_NO_ERROR(); +} + +using namespace egl_platform; + +DrawCallPerfParams DrawCallPerfD3D11Params(bool useNullDevice, bool renderToTexture) +{ + DrawCallPerfParams params; + params.eglParameters = useNullDevice ? D3D11_NULL() : D3D11(); + params.useFBO = renderToTexture; + return params; +} + +DrawCallPerfParams DrawCallPerfD3D9Params(bool useNullDevice, bool renderToTexture) +{ + DrawCallPerfParams params; + params.eglParameters = useNullDevice ? D3D9_NULL() : D3D9(); + params.useFBO = renderToTexture; + return params; +} + +DrawCallPerfParams DrawCallPerfOpenGLParams(bool useNullDevice, bool renderToTexture) +{ + DrawCallPerfParams params; + params.eglParameters = useNullDevice ? OPENGL_NULL() : OPENGL(); + params.useFBO = renderToTexture; + return params; +} + +DrawCallPerfParams DrawCallPerfValidationOnly() +{ + DrawCallPerfParams params; + params.eglParameters = DEFAULT(); + params.iterations = 10000; + params.numTris = 0; + params.runTimeSeconds = 5.0; + return params; +} + +TEST_P(DrawCallPerfBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(DrawCallPerfBenchmark, + DrawCallPerfD3D9Params(false, false), + DrawCallPerfD3D9Params(true, false), + DrawCallPerfD3D11Params(false, false), + DrawCallPerfD3D11Params(true, false), + DrawCallPerfD3D11Params(true, true), + DrawCallPerfOpenGLParams(false, false), + DrawCallPerfOpenGLParams(true, false), + DrawCallPerfOpenGLParams(true, true), + DrawCallPerfValidationOnly()); + +} // namespace diff --git a/gfx/angle/src/tests/perf_tests/DynamicPromotionPerfTest.cpp b/gfx/angle/src/tests/perf_tests/DynamicPromotionPerfTest.cpp new file mode 100755 index 000000000..738314354 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/DynamicPromotionPerfTest.cpp @@ -0,0 +1,189 @@ +// +// Copyright 2016 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. +// +// DynamicPromotionPerfTest: +// Tests that ANGLE will promote buffer specfied with DYNAMIC usage to static after a number of +// iterations without changing the data. It specifically affects the D3D back-end, which treats +// dynamic and static buffers quite differently. +// + +#include "ANGLEPerfTest.h" +#include "random_utils.h" +#include "shader_utils.h" +#include "Vector.h" + +using namespace angle; + +namespace +{ + +struct DynamicPromotionParams final : public RenderTestParams +{ + DynamicPromotionParams(); + std::string suffix() const override; + + size_t vertexCount; + unsigned int iterations; +}; + +DynamicPromotionParams::DynamicPromotionParams() : vertexCount(1024), iterations(4) +{ +} + +std::string DynamicPromotionParams::suffix() const +{ + return RenderTestParams::suffix(); +} + +std::ostream &operator<<(std::ostream &os, const DynamicPromotionParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +class DynamicPromotionPerfTest : public ANGLERenderTest, + public testing::WithParamInterface<DynamicPromotionParams> +{ + public: + DynamicPromotionPerfTest(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint mProgram; + GLuint mElementArrayBuffer; + GLuint mArrayBuffer; +}; + +DynamicPromotionPerfTest::DynamicPromotionPerfTest() + : ANGLERenderTest("DynamicPromotion", GetParam()), + mProgram(0), + mElementArrayBuffer(0), + mArrayBuffer(0) +{ +} + +void DynamicPromotionPerfTest::initializeBenchmark() +{ + const std::string &vertexShaderSource = + "attribute vec2 position;\n" + "attribute vec3 color;\n" + "varying vec3 vColor;\n" + "void main()\n" + "{\n" + " vColor = color;\n" + " gl_Position = vec4(position, 0, 1);\n" + "}"; + + const std::string &fragmentShaderSource = + "varying mediump vec3 vColor;\n" + "void main()\n" + "{\n" + " gl_FragColor = vec4(vColor, 1);\n" + "}"; + + mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource); + ASSERT_NE(0u, mProgram); + + const size_t vertexCount = GetParam().vertexCount; + + std::vector<GLushort> indexData; + std::vector<Vector2> positionData; + std::vector<Vector3> colorData; + + ASSERT_GE(static_cast<size_t>(std::numeric_limits<GLushort>::max()), vertexCount); + + RNG rng(1); + + for (size_t index = 0; index < vertexCount; ++index) + { + indexData.push_back(static_cast<GLushort>(index)); + + Vector2 position(rng.randomNegativeOneToOne(), rng.randomNegativeOneToOne()); + positionData.push_back(position); + + Vector3 color(rng.randomFloat(), rng.randomFloat(), rng.randomFloat()); + colorData.push_back(color); + } + + glGenBuffers(1, &mElementArrayBuffer); + glGenBuffers(1, &mArrayBuffer); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementArrayBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mArrayBuffer); + + GLsizeiptr elementArraySize = sizeof(GLushort) * vertexCount; + GLsizeiptr positionArraySize = sizeof(Vector2) * vertexCount; + GLsizeiptr colorArraySize = sizeof(Vector3) * vertexCount; + + // The DYNAMIC_DRAW usage is the key to the test. + glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementArraySize, indexData.data(), GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, positionArraySize + colorArraySize, nullptr, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, positionArraySize, positionData.data()); + glBufferSubData(GL_ARRAY_BUFFER, positionArraySize, colorArraySize, colorData.data()); + + glUseProgram(mProgram); + GLint positionLocation = glGetAttribLocation(mProgram, "position"); + ASSERT_NE(-1, positionLocation); + GLint colorLocation = glGetAttribLocation(mProgram, "color"); + ASSERT_NE(-1, colorLocation); + + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 0, + reinterpret_cast<const GLvoid *>(positionArraySize)); + + glEnableVertexAttribArray(positionLocation); + glEnableVertexAttribArray(colorLocation); + + ASSERT_GL_NO_ERROR(); +} + +void DynamicPromotionPerfTest::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mElementArrayBuffer); + glDeleteBuffers(1, &mArrayBuffer); +} + +void DynamicPromotionPerfTest::drawBenchmark() +{ + unsigned int iterations = GetParam().iterations; + size_t vertexCount = GetParam().vertexCount; + + glClear(GL_COLOR_BUFFER_BIT); + for (unsigned int count = 0; count < iterations; ++count) + { + glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(vertexCount), GL_UNSIGNED_SHORT, nullptr); + } + + ASSERT_GL_NO_ERROR(); +} + +DynamicPromotionParams DynamicPromotionD3D11Params() +{ + DynamicPromotionParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +DynamicPromotionParams DynamicPromotionD3D9Params() +{ + DynamicPromotionParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +TEST_P(DynamicPromotionPerfTest, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(DynamicPromotionPerfTest, + DynamicPromotionD3D11Params(), + DynamicPromotionD3D9Params()); + +} // anonymous namespace diff --git a/gfx/angle/src/tests/perf_tests/EGLInitializePerf.cpp b/gfx/angle/src/tests/perf_tests/EGLInitializePerf.cpp new file mode 100755 index 000000000..210ba2745 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/EGLInitializePerf.cpp @@ -0,0 +1,161 @@ +// +// 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. +// +// EGLInitializePerfTest: +// Performance test for device creation. +// + +#include "ANGLEPerfTest.h" +#include "Timer.h" +#include "test_utils/angle_test_configs.h" +#include "test_utils/angle_test_instantiate.h" +#include "platform/Platform.h" + +using namespace testing; + +namespace +{ + +// Only applies to D3D11 +class CapturePlatform : public angle::Platform +{ + public: + CapturePlatform() + : mTimer(CreateTimer()), + mLoadDLLsMS(0), + mCreateDeviceMS(0), + mInitResourcesMS(0) + { + mTimer->start(); + } + + double currentTime() override; + void histogramCustomCounts( + const char *name, int sample, int min, int max, int bucketCount) override; + + size_t getLoadDLLsMS() const { return mLoadDLLsMS; } + size_t getCreateDeviceMS() const { return mCreateDeviceMS; } + size_t getInitResourcesMS() const { return mInitResourcesMS; } + + private: + Timer *mTimer; + size_t mLoadDLLsMS; + size_t mCreateDeviceMS; + size_t mInitResourcesMS; +}; + +double CapturePlatform::currentTime() +{ + return mTimer->getElapsedTime(); +} + +void CapturePlatform::histogramCustomCounts( + const char *name, int sample, int /*min*/, int /*max*/, int /*bucketCount*/) +{ + // These must match the names of the histograms. + if (strcmp(name, "GPU.ANGLE.Renderer11InitializeDLLsMS") == 0) + { + mLoadDLLsMS += static_cast<size_t>(sample); + } + // Note: not captured in debug, due to creating a debug device + else if (strcmp(name, "GPU.ANGLE.D3D11CreateDeviceMS") == 0) + { + mCreateDeviceMS += static_cast<size_t>(sample); + } + else if (strcmp(name, "GPU.ANGLE.Renderer11InitializeDeviceMS") == 0) + { + mInitResourcesMS += static_cast<size_t>(sample); + } +} + +class EGLInitializePerfTest : public ANGLEPerfTest, + public WithParamInterface<angle::PlatformParameters> +{ + public: + EGLInitializePerfTest(); + ~EGLInitializePerfTest(); + + void step() override; + void TearDown() override; + + private: + OSWindow *mOSWindow; + EGLDisplay mDisplay; + CapturePlatform mCapturePlatform; +}; + +EGLInitializePerfTest::EGLInitializePerfTest() + : ANGLEPerfTest("EGLInitialize", "_run"), + mOSWindow(nullptr), + mDisplay(EGL_NO_DISPLAY) +{ + auto platform = GetParam().eglParameters; + + std::vector<EGLint> displayAttributes; + displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); + displayAttributes.push_back(platform.renderer); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE); + displayAttributes.push_back(platform.majorVersion); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE); + displayAttributes.push_back(platform.minorVersion); + + if (platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE || + platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE); + displayAttributes.push_back(platform.deviceType); + } + displayAttributes.push_back(EGL_NONE); + + mOSWindow = CreateOSWindow(); + mOSWindow->initialize("EGLInitialize Test", 64, 64); + + auto eglGetPlatformDisplayEXT = + reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); + if (eglGetPlatformDisplayEXT == nullptr) + { + std::cerr << "Error getting platform display!" << std::endl; + return; + } + + mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, + reinterpret_cast<void *>(mOSWindow->getNativeDisplay()), + &displayAttributes[0]); + + ANGLEPlatformInitialize(&mCapturePlatform); +} + +EGLInitializePerfTest::~EGLInitializePerfTest() +{ + SafeDelete(mOSWindow); +} + +void EGLInitializePerfTest::step() +{ + ASSERT_NE(EGL_NO_DISPLAY, mDisplay); + + EGLint majorVersion, minorVersion; + ASSERT_EQ(static_cast<EGLBoolean>(EGL_TRUE), eglInitialize(mDisplay, &majorVersion, &minorVersion)); + ASSERT_EQ(static_cast<EGLBoolean>(EGL_TRUE), eglTerminate(mDisplay)); +} + +void EGLInitializePerfTest::TearDown() +{ + ANGLEPerfTest::TearDown(); + printResult("LoadDLLs", normalizedTime(mCapturePlatform.getLoadDLLsMS()), "ms", true); + printResult("D3D11CreateDevice", normalizedTime(mCapturePlatform.getCreateDeviceMS()), "ms", true); + printResult("InitResources", normalizedTime(mCapturePlatform.getInitResourcesMS()), "ms", true); + + ANGLEPlatformShutdown(); +} + +TEST_P(EGLInitializePerfTest, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(EGLInitializePerfTest, angle::ES2_D3D11()); + +} // namespace diff --git a/gfx/angle/src/tests/perf_tests/IndexConversionPerf.cpp b/gfx/angle/src/tests/perf_tests/IndexConversionPerf.cpp new file mode 100755 index 000000000..d05e79d09 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/IndexConversionPerf.cpp @@ -0,0 +1,271 @@ +// +// 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. +// +// IndexConversionPerf: +// Performance tests for ANGLE index conversion in D3D11. +// + +#include <sstream> + +#include "ANGLEPerfTest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct IndexConversionPerfParams final : public RenderTestParams +{ + std::string suffix() const override + { + std::stringstream strstr; + + if (indexRangeOffset > 0) + { + strstr << "_index_range"; + } + + strstr << RenderTestParams::suffix(); + + return strstr.str(); + } + + unsigned int iterations; + unsigned int numIndexTris; + + // A second test, which covers using index ranges with an offset. + unsigned int indexRangeOffset; +}; + +// Provide a custom gtest parameter name function for IndexConversionPerfParams. +std::ostream &operator<<(std::ostream &stream, const IndexConversionPerfParams ¶m) +{ + stream << param.suffix().substr(1); + return stream; +} + +class IndexConversionPerfTest : public ANGLERenderTest, + public ::testing::WithParamInterface<IndexConversionPerfParams> +{ + public: + IndexConversionPerfTest(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + void updateBufferData(); + void drawConversion(); + void drawIndexRange(); + + GLuint mProgram; + GLuint mVertexBuffer; + GLuint mIndexBuffer; + std::vector<GLushort> mIndexData; +}; + +IndexConversionPerfTest::IndexConversionPerfTest() + : ANGLERenderTest("IndexConversionPerfTest", GetParam()), + mProgram(0), + mVertexBuffer(0), + mIndexBuffer(0) +{ + mRunTimeSeconds = 3.0; +} + +void IndexConversionPerfTest::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(0u, params.iterations); + ASSERT_LT(0u, params.numIndexTris); + + const std::string vs = SHADER_SOURCE + ( + attribute vec2 vPosition; + uniform float uScale; + uniform float uOffset; + void main() + { + gl_Position = vec4(vPosition * vec2(uScale) - vec2(uOffset), 0, 1); + } + ); + + const std::string fs = SHADER_SOURCE + ( + precision mediump float; + void main() + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + ); + + mProgram = CompileProgram(vs, fs); + ASSERT_NE(0u, mProgram); + + // Use the program object + glUseProgram(mProgram); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + // Initialize the vertex data + std::vector<GLfloat> floatData; + + size_t numTris = std::numeric_limits<GLushort>::max() / 3 + 1; + for (size_t triIndex = 0; triIndex < numTris; ++triIndex) + { + floatData.push_back(1); + floatData.push_back(2); + floatData.push_back(0); + floatData.push_back(0); + floatData.push_back(2); + floatData.push_back(0); + } + + glGenBuffers(1, &mVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, floatData.size() * sizeof(GLfloat), &floatData[0], GL_STATIC_DRAW); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + // Initialize the index buffer + for (unsigned int triIndex = 0; triIndex < params.numIndexTris; ++triIndex) + { + // Handle two different types of tests, one with index conversion triggered by a -1 index. + if (params.indexRangeOffset == 0) + { + mIndexData.push_back(std::numeric_limits<GLushort>::max()); + } + else + { + mIndexData.push_back(0); + } + + mIndexData.push_back(1); + mIndexData.push_back(2); + } + + glGenBuffers(1, &mIndexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); + updateBufferData(); + + // Set the viewport + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + GLfloat scale = 0.5f; + GLfloat offset = 0.5f; + + glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale); + glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset); + + ASSERT_GL_NO_ERROR(); +} + +void IndexConversionPerfTest::updateBufferData() +{ + glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexData.size() * sizeof(mIndexData[0]), &mIndexData[0], GL_STATIC_DRAW); +} + +void IndexConversionPerfTest::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mVertexBuffer); + glDeleteBuffers(1, &mIndexBuffer); +} + +void IndexConversionPerfTest::drawBenchmark() +{ + const auto ¶ms = GetParam(); + + if (params.indexRangeOffset == 0) + { + drawConversion(); + } + else + { + drawIndexRange(); + } +} + +void IndexConversionPerfTest::drawConversion() +{ + const auto ¶ms = GetParam(); + + // Trigger an update to ensure we convert once a frame + updateBufferData(); + + for (unsigned int it = 0; it < params.iterations; it++) + { + glDrawElements(GL_TRIANGLES, + static_cast<GLsizei>(params.numIndexTris * 3 - 1), + GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid*>(0)); + } + + ASSERT_GL_NO_ERROR(); +} + +void IndexConversionPerfTest::drawIndexRange() +{ + const auto ¶ms = GetParam(); + + unsigned int indexCount = 3; + size_t offset = static_cast<size_t>(indexCount * getNumStepsPerformed()); + + offset %= (params.numIndexTris * 3); + + // This test increments an offset each step. Drawing repeatedly may cause the system memory + // to release. Then, using a fresh offset will require index range validation, which pages + // it back in. The performance should be good even if the data is was used quite a bit. + for (unsigned int it = 0; it < params.iterations; it++) + { + glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indexCount), GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid *>(offset)); + } + + ASSERT_GL_NO_ERROR(); +} + +IndexConversionPerfParams IndexConversionPerfD3D11Params() +{ + IndexConversionPerfParams params; + params.eglParameters = egl_platform::D3D11_NULL(); + params.majorVersion = 2; + params.minorVersion = 0; + params.windowWidth = 256; + params.windowHeight = 256; + params.iterations = 225; + params.numIndexTris = 3000; + params.indexRangeOffset = 0; + return params; +} + +IndexConversionPerfParams IndexRangeOffsetPerfD3D11Params() +{ + IndexConversionPerfParams params; + params.eglParameters = egl_platform::D3D11_NULL(); + params.majorVersion = 2; + params.minorVersion = 0; + params.windowWidth = 256; + params.windowHeight = 256; + params.iterations = 16; + params.numIndexTris = 50000; + params.indexRangeOffset = 64; + return params; +} + +TEST_P(IndexConversionPerfTest, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(IndexConversionPerfTest, + IndexConversionPerfD3D11Params(), + IndexRangeOffsetPerfD3D11Params()); + +} // namespace diff --git a/gfx/angle/src/tests/perf_tests/IndexDataManagerTest.cpp b/gfx/angle/src/tests/perf_tests/IndexDataManagerTest.cpp new file mode 100755 index 000000000..696b81bb5 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/IndexDataManagerTest.cpp @@ -0,0 +1,186 @@ +// +// 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. +// +// IndexDataManagerPerfTest: +// Performance test for index buffer management. +// + +#include "ANGLEPerfTest.h" + +#include <gmock/gmock.h> + +#include "angle_unittests_utils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" + +using namespace testing; + +namespace +{ + +class MockIndexBuffer : public rx::IndexBuffer +{ + public: + MockIndexBuffer(unsigned int bufferSize, GLenum indexType) + : mBufferSize(bufferSize), + mIndexType(indexType) + { + } + + MOCK_METHOD3(initialize, gl::Error(unsigned int, GLenum, bool)); + MOCK_METHOD3(mapBuffer, gl::Error(unsigned int, unsigned int, void**)); + MOCK_METHOD0(unmapBuffer, gl::Error()); + MOCK_METHOD0(discard, gl::Error()); + MOCK_METHOD2(setSize, gl::Error(unsigned int, GLenum)); + + // inlined for speed + GLenum getIndexType() const override { return mIndexType; } + unsigned int getBufferSize() const override { return mBufferSize; } + + private: + unsigned int mBufferSize; + GLenum mIndexType; +}; + +class MockBufferFactoryD3D : public rx::BufferFactoryD3D +{ + public: + MockBufferFactoryD3D(unsigned int bufferSize, GLenum indexType) + : mBufferSize(bufferSize), + mIndexType(indexType) + { + } + + MOCK_METHOD0(createVertexBuffer, rx::VertexBuffer*()); + MOCK_CONST_METHOD1(getVertexConversionType, rx::VertexConversionType(gl::VertexFormatType)); + MOCK_CONST_METHOD1(getVertexComponentType, GLenum(gl::VertexFormatType)); + MOCK_CONST_METHOD3(getVertexSpaceRequired, + gl::ErrorOrResult<unsigned int>(const gl::VertexAttribute &, + GLsizei, + GLsizei)); + + // Dependency injection + rx::IndexBuffer* createIndexBuffer() override + { + return new MockIndexBuffer(mBufferSize, mIndexType); + } + + private: + unsigned int mBufferSize; + GLenum mIndexType; +}; + +class MockBufferD3D : public rx::BufferD3D +{ + public: + MockBufferD3D(rx::BufferFactoryD3D *factory) : BufferD3D(mockState, factory), mData() {} + + // BufferImpl + gl::Error setData(GLenum target, const void *data, size_t size, GLenum) override + { + mData.resize(size); + if (data && size > 0) + { + memcpy(&mData[0], data, size); + } + return gl::Error(GL_NO_ERROR); + } + + MOCK_METHOD4(setSubData, gl::Error(GLenum, const void *, size_t, size_t)); + MOCK_METHOD4(copySubData, gl::Error(BufferImpl*, GLintptr, GLintptr, GLsizeiptr)); + MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **)); + MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **)); + MOCK_METHOD1(unmap, gl::Error(GLboolean *)); + + // BufferD3D + MOCK_METHOD0(markTransformFeedbackUsage, gl::Error()); + + // inlined for speed + bool supportsDirectBinding() const override { return false; } + size_t getSize() const override { return mData.size(); } + + gl::Error getData(const uint8_t **outData) override + { + *outData = &mData[0]; + return gl::Error(GL_NO_ERROR); + } + + private: + gl::BufferState mockState; + std::vector<uint8_t> mData; +}; + +class MockGLFactoryD3D : public rx::MockGLFactory +{ + public: + MockGLFactoryD3D(MockBufferFactoryD3D *bufferFactory) : mBufferFactory(bufferFactory) {} + + rx::BufferImpl *createBuffer(const gl::BufferState &state) override + { + MockBufferD3D *mockBufferD3D = new MockBufferD3D(mBufferFactory); + + EXPECT_CALL(*mBufferFactory, createVertexBuffer()) + .WillOnce(Return(nullptr)) + .RetiresOnSaturation(); + mockBufferD3D->initializeStaticData(); + + return mockBufferD3D; + } + + MockBufferFactoryD3D *mBufferFactory; +}; + +class IndexDataManagerPerfTest : public ANGLEPerfTest +{ + public: + IndexDataManagerPerfTest(); + + void step() override; + + rx::IndexDataManager mIndexDataManager; + GLsizei mIndexCount; + unsigned int mBufferSize; + MockBufferFactoryD3D mMockBufferFactory; + MockGLFactoryD3D mMockGLFactory; + gl::Buffer mIndexBuffer; +}; + +IndexDataManagerPerfTest::IndexDataManagerPerfTest() + : ANGLEPerfTest("IndexDataManger", "_run"), + mIndexDataManager(&mMockBufferFactory, rx::RENDERER_D3D11), + mIndexCount(4000), + mBufferSize(mIndexCount * sizeof(GLushort)), + mMockBufferFactory(mBufferSize, GL_UNSIGNED_SHORT), + mMockGLFactory(&mMockBufferFactory), + mIndexBuffer(&mMockGLFactory, 1) +{ + std::vector<GLushort> indexData(mIndexCount); + for (GLsizei index = 0; index < mIndexCount; ++index) + { + indexData[index] = static_cast<GLushort>(index); + } + mIndexBuffer.bufferData(GL_ARRAY_BUFFER, &indexData[0], indexData.size() * sizeof(GLushort), + GL_STATIC_DRAW); +} + +void IndexDataManagerPerfTest::step() +{ + rx::TranslatedIndexData translatedIndexData; + for (unsigned int iteration = 0; iteration < 100; ++iteration) + { + mIndexBuffer.getIndexRange(GL_UNSIGNED_SHORT, 0, mIndexCount, false, + &translatedIndexData.indexRange); + mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr, + &translatedIndexData, false); + } +} + +TEST_F(IndexDataManagerPerfTest, Run) +{ + run(); +} + +} // anonymous namespace diff --git a/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp b/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp new file mode 100755 index 000000000..eb02c10e9 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp @@ -0,0 +1,366 @@ +// +// 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 <cmath> +#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 - std::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(); +} + +Vector3 RandomVector3(RNG *rng) +{ + return Vector3(rng->randomNegativeOneToOne(), rng->randomNegativeOneToOne(), + rng->randomNegativeOneToOne()); +} + +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 drawBenchmark() override; + + private: + GLuint mProgram; + std::vector<GLuint> mBuffers; + GLuint mNumPoints; + std::vector<Vector3> mTranslateData; + std::vector<float> mSizeData; + std::vector<Vector3> mColorData; + angle::RNG mRNG; +}; + +InstancingPerfBenchmark::InstancingPerfBenchmark() + : ANGLERenderTest("InstancingPerf", GetParam()), mProgram(0), mNumPoints(75000) +{ + mRunTimeSeconds = GetParam().runTimeSeconds; +} + +void InstancingPerfBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(0u, 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_NE(0u, mProgram); + + 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 = RandomVector3(&mRNG); + 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 = RandomVector3(&mRNG); + 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::drawBenchmark() +{ + glClear(GL_COLOR_BUFFER_BIT); + + 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 diff --git a/gfx/angle/src/tests/perf_tests/InterleavedAttributeData.cpp b/gfx/angle/src/tests/perf_tests/InterleavedAttributeData.cpp new file mode 100755 index 000000000..15e2a5b14 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/InterleavedAttributeData.cpp @@ -0,0 +1,231 @@ +// +// Copyright (c) 2014 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. +// +// InterleavedAttributeData: +// Performance test for draws using interleaved attribute data in vertex buffers. +// + +#include <sstream> + +#include "ANGLEPerfTest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct InterleavedAttributeDataParams final : public RenderTestParams +{ + InterleavedAttributeDataParams() + { + // Common default values + majorVersion = 2; + minorVersion = 0; + windowWidth = 512; + windowHeight = 512; + numSprites = 3000; + } + + // static parameters + unsigned int numSprites; +}; + +std::ostream &operator<<(std::ostream &os, const InterleavedAttributeDataParams ¶ms) +{ + os << params.suffix().substr(1); + + if (params.eglParameters.majorVersion != EGL_DONT_CARE) + { + os << "_" << params.eglParameters.majorVersion << "_" << params.eglParameters.minorVersion; + } + + return os; +} + +class InterleavedAttributeDataBenchmark + : public ANGLERenderTest, + public ::testing::WithParamInterface<InterleavedAttributeDataParams> +{ + public: + InterleavedAttributeDataBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint mPointSpriteProgram; + GLuint mPositionColorBuffer[2]; + + // The buffers contain two floats and 3 unsigned bytes per point sprite + const size_t mBytesPerSprite = 2 * sizeof(float) + 3; +}; + +InterleavedAttributeDataBenchmark::InterleavedAttributeDataBenchmark() + : ANGLERenderTest("InterleavedAttributeData", GetParam()), mPointSpriteProgram(0) +{ +} + +void InterleavedAttributeDataBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + // Compile point sprite shaders + const std::string vs = + "attribute vec4 aPosition;" + "attribute vec4 aColor;" + "varying vec4 vColor;" + "void main()" + "{" + " gl_PointSize = 25.0;" + " gl_Position = aPosition;" + " vColor = aColor;" + "}"; + + const std::string fs = + "precision mediump float;" + "varying vec4 vColor;" + "void main()" + "{" + " gl_FragColor = vColor;" + "}"; + + mPointSpriteProgram = CompileProgram(vs, fs); + ASSERT_NE(0u, mPointSpriteProgram); + + glClearColor(0.0f, 1.0f, 0.0f, 1.0f); + + for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++) + { + // Set up initial data for pointsprite positions and colors + std::vector<uint8_t> positionColorData(mBytesPerSprite * params.numSprites); + for (unsigned int j = 0; j < params.numSprites; j++) + { + float pointSpriteX = + (static_cast<float>(rand() % getWindow()->getWidth()) / getWindow()->getWidth()) * + 2.0f - 1.0f; + float pointSpriteY = + (static_cast<float>(rand() % getWindow()->getHeight()) / getWindow()->getHeight()) * + 2.0f - 1.0f; + GLubyte pointSpriteRed = static_cast<GLubyte>(rand() % 255); + GLubyte pointSpriteGreen = static_cast<GLubyte>(rand() % 255); + GLubyte pointSpriteBlue = static_cast<GLubyte>(rand() % 255); + + // Add position data for the pointsprite + *reinterpret_cast<float *>( + &(positionColorData[j * mBytesPerSprite + 0 * sizeof(float) + 0])) = + pointSpriteX; // X + *reinterpret_cast<float *>( + &(positionColorData[j * mBytesPerSprite + 1 * sizeof(float) + 0])) = + pointSpriteY; // Y + + // Add color data for the pointsprite + positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 0] = pointSpriteRed; // R + positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 1] = pointSpriteGreen; // G + positionColorData[j * mBytesPerSprite + 2 * sizeof(float) + 2] = pointSpriteBlue; // B + } + + // Generate the GL buffer with the position/color data + glGenBuffers(1, &mPositionColorBuffer[i]); + glBindBuffer(GL_ARRAY_BUFFER, mPositionColorBuffer[i]); + glBufferData(GL_ARRAY_BUFFER, params.numSprites * mBytesPerSprite, &(positionColorData[0]), + GL_STATIC_DRAW); + } + + ASSERT_GL_NO_ERROR(); +} + +void InterleavedAttributeDataBenchmark::destroyBenchmark() +{ + glDeleteProgram(mPointSpriteProgram); + + for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++) + { + glDeleteBuffers(1, &mPositionColorBuffer[i]); + } +} + +void InterleavedAttributeDataBenchmark::drawBenchmark() +{ + glClear(GL_COLOR_BUFFER_BIT); + + for (size_t k = 0; k < 20; k++) + { + for (size_t i = 0; i < ArraySize(mPositionColorBuffer); i++) + { + // Firstly get the attribute locations for the program + glUseProgram(mPointSpriteProgram); + GLint positionLocation = glGetAttribLocation(mPointSpriteProgram, "aPosition"); + ASSERT_NE(positionLocation, -1); + GLint colorLocation = glGetAttribLocation(mPointSpriteProgram, "aColor"); + ASSERT_NE(colorLocation, -1); + + // Bind the position data from one buffer + glBindBuffer(GL_ARRAY_BUFFER, mPositionColorBuffer[i]); + glEnableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, + static_cast<GLsizei>(mBytesPerSprite), 0); + + // But bind the color data from the other buffer. + glBindBuffer(GL_ARRAY_BUFFER, + mPositionColorBuffer[(i + 1) % ArraySize(mPositionColorBuffer)]); + glEnableVertexAttribArray(colorLocation); + glVertexAttribPointer(colorLocation, 3, GL_UNSIGNED_BYTE, GL_TRUE, + static_cast<GLsizei>(mBytesPerSprite), + reinterpret_cast<void *>(2 * sizeof(float))); + + // Then draw the colored pointsprites + glDrawArrays(GL_POINTS, 0, GetParam().numSprites); + glFlush(); + + glDisableVertexAttribArray(positionLocation); + glDisableVertexAttribArray(colorLocation); + } + } + + ASSERT_GL_NO_ERROR(); +} + +TEST_P(InterleavedAttributeDataBenchmark, Run) +{ + run(); +} + +InterleavedAttributeDataParams D3D11Params() +{ + InterleavedAttributeDataParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +InterleavedAttributeDataParams D3D11_9_3Params() +{ + InterleavedAttributeDataParams params; + params.eglParameters = egl_platform::D3D11_FL9_3(); + return params; +} + +InterleavedAttributeDataParams D3D9Params() +{ + InterleavedAttributeDataParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +InterleavedAttributeDataParams OpenGLParams() +{ + InterleavedAttributeDataParams params; + params.eglParameters = egl_platform::OPENGL(); + return params; +} + +ANGLE_INSTANTIATE_TEST(InterleavedAttributeDataBenchmark, + D3D11Params(), + D3D11_9_3Params(), + D3D9Params(), + OpenGLParams()); + +} // anonymous namespace diff --git a/gfx/angle/src/tests/perf_tests/PointSprites.cpp b/gfx/angle/src/tests/perf_tests/PointSprites.cpp new file mode 100755 index 000000000..b0b23109b --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/PointSprites.cpp @@ -0,0 +1,230 @@ +// +// Copyright (c) 2014 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. +// +// PointSpritesBenchmark: +// Performance test for ANGLE point sprites. +// +// +#include "ANGLEPerfTest.h" + +#include <iostream> +#include <sstream> + +#include "shader_utils.h" +#include "random_utils.h" + +using namespace angle; + +namespace +{ + +struct PointSpritesParams final : public RenderTestParams +{ + PointSpritesParams() + { + // Common default params + majorVersion = 2; + minorVersion = 0; + windowWidth = 1280; + windowHeight = 720; + iterations = 100; + count = 10; + size = 3.0f; + numVaryings = 3; + } + + std::string suffix() const override; + + unsigned int count; + float size; + unsigned int numVaryings; + + // static parameters + unsigned int iterations; +}; + +std::ostream &operator<<(std::ostream &os, const PointSpritesParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +class PointSpritesBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<PointSpritesParams> +{ + public: + PointSpritesBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint mProgram; + GLuint mBuffer; + RNG mRNG; +}; + +std::string PointSpritesParams::suffix() const +{ + std::stringstream strstr; + + strstr << RenderTestParams::suffix() + << "_" << count << "_" << size << "px" + << "_" << numVaryings << "vars"; + + return strstr.str(); +} + +PointSpritesBenchmark::PointSpritesBenchmark() + : ANGLERenderTest("PointSprites", GetParam()), mRNG(1) +{ +} + +void PointSpritesBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(0u, params.iterations); + + std::stringstream vstrstr; + + // Verify "numVaryings" is within MAX_VARYINGS limit + GLint maxVaryings; + glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); + + if (params.numVaryings > static_cast<unsigned int>(maxVaryings)) + { + FAIL() << "Varying count (" << params.numVaryings << ")" + << " exceeds maximum varyings: " << maxVaryings << std::endl; + } + + vstrstr << "attribute vec2 vPosition;\n" + "uniform float uPointSize;\n"; + + for (unsigned int varCount = 0; varCount < params.numVaryings; varCount++) + { + vstrstr << "varying vec4 v" << varCount << ";\n"; + } + + vstrstr << "void main()\n" + "{\n"; + + for (unsigned int varCount = 0; varCount < params.numVaryings; varCount++) + { + vstrstr << " v" << varCount << " = vec4(1.0);\n"; + } + + vstrstr << " gl_Position = vec4(vPosition, 0, 1.0);\n" + " gl_PointSize = uPointSize;\n" + "}"; + + std::stringstream fstrstr; + + fstrstr << "precision mediump float;\n"; + + for (unsigned int varCount = 0; varCount < params.numVaryings; varCount++) + { + fstrstr << "varying vec4 v" << varCount << ";\n"; + } + + fstrstr << "void main()\n" + "{\n" + " vec4 colorOut = vec4(1.0, 0.0, 0.0, 1.0);\n"; + + for (unsigned int varCount = 0; varCount < params.numVaryings; varCount++) + { + fstrstr << " colorOut.r += v" << varCount << ".r;\n"; + } + + fstrstr << " gl_FragColor = colorOut;\n" + "}\n"; + + mProgram = CompileProgram(vstrstr.str(), fstrstr.str()); + ASSERT_NE(0u, mProgram); + + // Use the program object + glUseProgram(mProgram); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + std::vector<float> vertexPositions(params.count * 2); + for (size_t pointIndex = 0; pointIndex < vertexPositions.size(); ++pointIndex) + { + vertexPositions[pointIndex] = mRNG.randomNegativeOneToOne(); + } + + glGenBuffers(1, &mBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(float), &vertexPositions[0], GL_STATIC_DRAW); + + GLint positionLocation = glGetAttribLocation(mProgram, "vPosition"); + ASSERT_NE(-1, positionLocation); + + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + glEnableVertexAttribArray(positionLocation); + + // Set the viewport + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + GLint pointSizeLocation = glGetUniformLocation(mProgram, "uPointSize"); + ASSERT_NE(-1, pointSizeLocation); + + glUniform1f(pointSizeLocation, params.size); + + ASSERT_GL_NO_ERROR(); +} + +void PointSpritesBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mBuffer); +} + +void PointSpritesBenchmark::drawBenchmark() +{ + glClear(GL_COLOR_BUFFER_BIT); + + const auto ¶ms = GetParam(); + + for (unsigned int it = 0; it < params.iterations; it++) + { + //TODO(jmadill): Indexed point rendering. ANGLE is bad at this. + glDrawArrays(GL_POINTS, 0, params.count); + } + + ASSERT_GL_NO_ERROR(); +} + +PointSpritesParams D3D11Params() +{ + PointSpritesParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +PointSpritesParams D3D9Params() +{ + PointSpritesParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +PointSpritesParams OpenGLParams() +{ + PointSpritesParams params; + params.eglParameters = egl_platform::OPENGL(); + return params; +} + +} // namespace + +TEST_P(PointSpritesBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(PointSpritesBenchmark, + D3D11Params(), D3D9Params(), OpenGLParams()); diff --git a/gfx/angle/src/tests/perf_tests/TexSubImage.cpp b/gfx/angle/src/tests/perf_tests/TexSubImage.cpp new file mode 100755 index 000000000..3e4b5cf68 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/TexSubImage.cpp @@ -0,0 +1,298 @@ +// +// Copyright (c) 2014 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. +// +// TexSubImageBenchmark: +// Performace test for ANGLE texture updates. +// + +#include <sstream> + +#include "ANGLEPerfTest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct TexSubImageParams final : public RenderTestParams +{ + TexSubImageParams() + { + // Common default parameters + majorVersion = 2; + minorVersion = 0; + windowWidth = 512; + windowHeight = 512; + + imageWidth = 1024; + imageHeight = 1024; + subImageWidth = 64; + subImageHeight = 64; + iterations = 9; + } + + std::string suffix() const override; + + // Static parameters + int imageWidth; + int imageHeight; + int subImageWidth; + int subImageHeight; + unsigned int iterations; +}; + +std::ostream &operator<<(std::ostream &os, const TexSubImageParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +class TexSubImageBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<TexSubImageParams> +{ + public: + TexSubImageBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + GLuint createTexture(); + + // Handle to a program object + GLuint mProgram; + + // Attribute locations + GLint mPositionLoc; + GLint mTexCoordLoc; + + // Sampler location + GLint mSamplerLoc; + + // Texture handle + GLuint mTexture; + + // Buffer handle + GLuint mVertexBuffer; + GLuint mIndexBuffer; + + GLubyte *mPixels; +}; + +std::string TexSubImageParams::suffix() const +{ + // TODO(jmadill) + return RenderTestParams::suffix(); +} + +TexSubImageBenchmark::TexSubImageBenchmark() + : ANGLERenderTest("TexSubImage", GetParam()), + mProgram(0), + mPositionLoc(-1), + mTexCoordLoc(-1), + mSamplerLoc(-1), + mTexture(0), + mVertexBuffer(0), + mIndexBuffer(0), + mPixels(nullptr) +{ +} + +GLuint TexSubImageBenchmark::createTexture() +{ + const auto ¶ms = GetParam(); + + assert(params.iterations > 0); + + // Use tightly packed data + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // Generate a texture object + GLuint texture; + glGenTextures(1, &texture); + + // Bind the texture object + glBindTexture(GL_TEXTURE_2D, texture); + + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.imageWidth, params.imageHeight); + + // Set the filtering mode + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + return texture; +} + +void TexSubImageBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + const std::string vs = SHADER_SOURCE + ( + attribute vec4 a_position; + attribute vec2 a_texCoord; + varying vec2 v_texCoord; + void main() + { + gl_Position = a_position; + v_texCoord = a_texCoord; + } + ); + + const std::string fs = SHADER_SOURCE + ( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + void main() + { + gl_FragColor = texture2D(s_texture, v_texCoord); + } + ); + + mProgram = CompileProgram(vs, fs); + ASSERT_NE(0u, mProgram); + + // Get the attribute locations + mPositionLoc = glGetAttribLocation(mProgram, "a_position"); + mTexCoordLoc = glGetAttribLocation(mProgram, "a_texCoord"); + + // Get the sampler location + mSamplerLoc = glGetUniformLocation(mProgram, "s_texture"); + + // Build the vertex buffer + GLfloat vertices[] = + { + -0.5f, 0.5f, 0.0f, // Position 0 + 0.0f, 0.0f, // TexCoord 0 + -0.5f, -0.5f, 0.0f, // Position 1 + 0.0f, 1.0f, // TexCoord 1 + 0.5f, -0.5f, 0.0f, // Position 2 + 1.0f, 1.0f, // TexCoord 2 + 0.5f, 0.5f, 0.0f, // Position 3 + 1.0f, 0.0f // TexCoord 3 + }; + + glGenBuffers(1, &mVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + glGenBuffers(1, &mIndexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + // Load the texture + mTexture = createTexture(); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + mPixels = new GLubyte[params.subImageWidth * params.subImageHeight * 4]; + + // Fill the pixels structure with random data: + for (int y = 0; y < params.subImageHeight; ++y) + { + for (int x = 0; x < params.subImageWidth; ++x) + { + int offset = (x + (y * params.subImageWidth)) * 4; + mPixels[offset + 0] = rand() % 255; // Red + mPixels[offset + 1] = rand() % 255; // Green + mPixels[offset + 2] = rand() % 255; // Blue + mPixels[offset + 3] = 255; // Alpha + } + } + + ASSERT_GL_NO_ERROR(); +} + +void TexSubImageBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mVertexBuffer); + glDeleteBuffers(1, &mIndexBuffer); + glDeleteTextures(1, &mTexture); + delete[] mPixels; +} + +void TexSubImageBenchmark::drawBenchmark() +{ + // Set the viewport + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + // Clear the color buffer + glClear(GL_COLOR_BUFFER_BIT); + + // Use the program object + glUseProgram(mProgram); + + // Bind the buffers + glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); + + // Load the vertex position + glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0); + // Load the texture coordinate + glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + + glEnableVertexAttribArray(mPositionLoc); + glEnableVertexAttribArray(mTexCoordLoc); + + // Bind the texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mTexture); + + // Set the texture sampler to texture unit to 0 + glUniform1i(mSamplerLoc, 0); + + ASSERT_GL_NO_ERROR(); + + const auto ¶ms = GetParam(); + + for (unsigned int iteration = 0; iteration < params.iterations; ++iteration) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, + rand() % (params.imageWidth - params.subImageWidth), + rand() % (params.imageHeight - params.subImageHeight), + params.subImageWidth, params.subImageHeight, + GL_RGBA, GL_UNSIGNED_BYTE, mPixels); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); + } + + ASSERT_GL_NO_ERROR(); +} + +TexSubImageParams D3D11Params() +{ + TexSubImageParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +TexSubImageParams D3D9Params() +{ + TexSubImageParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +TexSubImageParams OpenGLParams() +{ + TexSubImageParams params; + params.eglParameters = egl_platform::OPENGL(); + return params; +} + +} // namespace + +TEST_P(TexSubImageBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(TexSubImageBenchmark, + D3D11Params(), D3D9Params(), OpenGLParams()); diff --git a/gfx/angle/src/tests/perf_tests/TextureSampling.cpp b/gfx/angle/src/tests/perf_tests/TextureSampling.cpp new file mode 100755 index 000000000..bc00acddf --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/TextureSampling.cpp @@ -0,0 +1,288 @@ +// +// Copyright (c) 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. +// +// TextureSamplingBenchmark: +// Performance test for texture sampling. The test generates a texture containing random data +// and then blurs it in a fragment shader using nearest neighbor sampling. The test is +// specifically designed to test overhead of GLSL's builtin texture*() functions that may result +// from how ANGLE translates them on each backend. +// + +#include "ANGLEPerfTest.h" + +#include <iostream> +#include <random> +#include <sstream> + +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct TextureSamplingParams final : public RenderTestParams +{ + TextureSamplingParams() + { + // Common default params + majorVersion = 2; + minorVersion = 0; + windowWidth = 720; + windowHeight = 720; + iterations = 4; + + numSamplers = 2; + textureSize = 32; + kernelSize = 3; + } + + std::string suffix() const override; + unsigned int numSamplers; + unsigned int textureSize; + unsigned int kernelSize; + + // static parameters + unsigned int iterations; +}; + +std::ostream &operator<<(std::ostream &os, const TextureSamplingParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +std::string TextureSamplingParams::suffix() const +{ + std::stringstream strstr; + + strstr << RenderTestParams::suffix() << "_" << numSamplers << "samplers"; + + return strstr.str(); +} + +class TextureSamplingBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<TextureSamplingParams> +{ + public: + TextureSamplingBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + void initShaders(); + void initVertexBuffer(); + void initTextures(); + + GLuint mProgram; + GLuint mBuffer; + std::vector<GLuint> mTextures; +}; + +TextureSamplingBenchmark::TextureSamplingBenchmark() + : ANGLERenderTest("TextureSampling", GetParam()), mProgram(0u), mBuffer(0u) +{ +} + +void TextureSamplingBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_LT(0u, params.iterations); + + // Verify "numSamplers" is within MAX_TEXTURE_IMAGE_UNITS limit + GLint maxTextureImageUnits; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits); + + if (params.numSamplers > static_cast<unsigned int>(maxTextureImageUnits)) + { + FAIL() << "Sampler count (" << params.numSamplers << ")" + << " exceeds maximum texture count: " << maxTextureImageUnits << std::endl; + } + initShaders(); + initVertexBuffer(); + initTextures(); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + ASSERT_GL_NO_ERROR(); +} + +void TextureSamplingBenchmark::initShaders() +{ + const auto ¶ms = GetParam(); + + std::stringstream vstrstr; + vstrstr << "attribute vec2 aPosition;\n" + "varying vec2 vTextureCoordinates;\n" + "void main()\n" + "{\n" + " vTextureCoordinates = (aPosition + vec2(1.0)) * 0.5;\n" + " gl_Position = vec4(aPosition, 0, 1.0);\n" + "}"; + + std::stringstream fstrstr; + fstrstr << "precision mediump float;\n" + "varying vec2 vTextureCoordinates;\n"; + for (unsigned int count = 0; count < params.numSamplers; count++) + { + fstrstr << "uniform sampler2D uSampler" << count << ";\n"; + } + fstrstr << "void main()\n" + "{\n" + " const float inverseTextureSize = 1.0 / " + << params.textureSize << ".0;\n" + " vec4 colorOut = vec4(0.0, 0.0, 0.0, 1.0);\n"; + for (unsigned int count = 0; count < params.numSamplers; count++) + { + fstrstr << " for (int x = 0; x < " << params.kernelSize << "; ++x)\n" + " {\n" + " for (int y = 0; y < " << params.kernelSize << "; ++y)\n" + " {\n" + " colorOut += texture2D(uSampler" << count + << ", vTextureCoordinates + vec2(x, y) * inverseTextureSize) * 0.1;\n" + " }\n" + " }\n"; + } + fstrstr << " gl_FragColor = colorOut;\n" + "}\n"; + + mProgram = CompileProgram(vstrstr.str(), fstrstr.str()); + ASSERT_NE(0u, mProgram); + + // Use the program object + glUseProgram(mProgram); +} + +void TextureSamplingBenchmark::initVertexBuffer() +{ + std::vector<float> vertexPositions(12); + { + // Bottom left triangle + vertexPositions[0] = -1.0f; + vertexPositions[1] = -1.0f; + vertexPositions[2] = 1.0f; + vertexPositions[3] = -1.0f; + vertexPositions[4] = -1.0f; + vertexPositions[5] = 1.0f; + + // Top right triangle + vertexPositions[6] = -1.0f; + vertexPositions[7] = 1.0f; + vertexPositions[8] = 1.0f; + vertexPositions[9] = -1.0f; + vertexPositions[10] = 1.0f; + vertexPositions[11] = 1.0f; + } + + glGenBuffers(1, &mBuffer); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(float), &vertexPositions[0], + GL_STATIC_DRAW); + + GLint positionLocation = glGetAttribLocation(mProgram, "aPosition"); + ASSERT_NE(-1, positionLocation); + + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + glEnableVertexAttribArray(positionLocation); +} + +void TextureSamplingBenchmark::initTextures() +{ + const auto ¶ms = GetParam(); + + unsigned int dataSize = params.textureSize * params.textureSize; + std::vector<unsigned int> randomTextureData; + randomTextureData.resize(dataSize); + + unsigned int pseudoRandom = 1u; + for (unsigned int i = 0; i < dataSize; ++i) + { + pseudoRandom = pseudoRandom * 1664525u + 1013904223u; + randomTextureData[i] = pseudoRandom; + } + + mTextures.resize(params.numSamplers); + glGenTextures(params.numSamplers, mTextures.data()); + for (unsigned int i = 0; i < params.numSamplers; ++i) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, mTextures[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, params.textureSize, params.textureSize, 0, GL_RGBA, + GL_UNSIGNED_BYTE, randomTextureData.data()); + } + + for (unsigned int count = 0; count < params.numSamplers; count++) + { + std::stringstream samplerstrstr; + samplerstrstr << "uSampler" << count; + GLint samplerLocation = glGetUniformLocation(mProgram, samplerstrstr.str().c_str()); + ASSERT_NE(-1, samplerLocation); + + glUniform1i(samplerLocation, count); + } +} + +void TextureSamplingBenchmark::destroyBenchmark() +{ + const auto ¶ms = GetParam(); + + glDeleteProgram(mProgram); + glDeleteBuffers(1, &mBuffer); + if (!mTextures.empty()) + { + glDeleteTextures(params.numSamplers, mTextures.data()); + } +} + +void TextureSamplingBenchmark::drawBenchmark() +{ + glClear(GL_COLOR_BUFFER_BIT); + + const auto ¶ms = GetParam(); + + for (unsigned int it = 0; it < params.iterations; ++it) + { + glDrawArrays(GL_TRIANGLES, 0, 6); + } + + ASSERT_GL_NO_ERROR(); +} + +TextureSamplingParams D3D11Params() +{ + TextureSamplingParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +TextureSamplingParams D3D9Params() +{ + TextureSamplingParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +TextureSamplingParams OpenGLParams() +{ + TextureSamplingParams params; + params.eglParameters = egl_platform::OPENGL(); + return params; +} + +} // anonymous namespace + +TEST_P(TextureSamplingBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(TextureSamplingBenchmark, D3D11Params(), D3D9Params(), OpenGLParams()); diff --git a/gfx/angle/src/tests/perf_tests/TexturesPerf.cpp b/gfx/angle/src/tests/perf_tests/TexturesPerf.cpp new file mode 100644 index 000000000..58e1a9ba6 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/TexturesPerf.cpp @@ -0,0 +1,293 @@ +// +// Copyright (c) 2016 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. +// +// TexturesPerf: +// Performance test for setting texture state. +// + +#include "ANGLEPerfTest.h" + +#include <iostream> +#include <random> +#include <sstream> + +#include "shader_utils.h" + +namespace angle +{ + +struct TexturesParams final : public RenderTestParams +{ + TexturesParams() + { + // Common default params + majorVersion = 2; + minorVersion = 0; + windowWidth = 720; + windowHeight = 720; + iterations = 256; + + numTextures = 8; + textureRebindFrequency = 5; + textureStateUpdateFrequency = 3; + textureMipCount = 8; + } + + std::string suffix() const override; + size_t numTextures; + size_t textureRebindFrequency; + size_t textureStateUpdateFrequency; + size_t textureMipCount; + + // static parameters + size_t iterations; +}; + +std::ostream &operator<<(std::ostream &os, const TexturesParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +std::string TexturesParams::suffix() const +{ + std::stringstream strstr; + + strstr << RenderTestParams::suffix(); + strstr << "_" << numTextures << "_textures"; + strstr << "_" << textureRebindFrequency << "_rebind"; + strstr << "_" << textureStateUpdateFrequency << "_state"; + strstr << "_" << textureMipCount << "_mips"; + + return strstr.str(); +} + +class TexturesBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<TexturesParams> +{ + public: + TexturesBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + void initShaders(); + void initTextures(); + + std::vector<GLuint> mTextures; + + GLuint mProgram; + std::vector<GLuint> mUniformLocations; +}; + +TexturesBenchmark::TexturesBenchmark() : ANGLERenderTest("Textures", GetParam()), mProgram(0u) +{ +} + +void TexturesBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_GT(params.iterations, 0u); + + // Verify the uniform counts are within the limits + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + if (params.numTextures > static_cast<size_t>(maxTextureUnits)) + { + FAIL() << "Texture count (" << params.numTextures << ")" + << " exceeds maximum texture unit count: " << maxTextureUnits << std::endl; + } + + initShaders(); + initTextures(); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + ASSERT_GL_NO_ERROR(); +} + +std::string GetUniformLocationName(size_t idx, bool vertexShader) +{ + std::stringstream strstr; + strstr << (vertexShader ? "vs" : "fs") << "_u_" << idx; + return strstr.str(); +} + +void TexturesBenchmark::initShaders() +{ + const auto ¶ms = GetParam(); + + std::string vs = + "void main()\n" + "{\n" + " gl_Position = vec4(0, 0, 0, 0);\n" + "}\n"; + + std::stringstream fstrstr; + for (size_t i = 0; i < params.numTextures; i++) + { + fstrstr << "uniform sampler2D tex" << i << ";"; + } + fstrstr << "void main()\n" + "{\n" + " gl_FragColor = vec4(0, 0, 0, 0)"; + for (size_t i = 0; i < params.numTextures; i++) + { + fstrstr << "+ texture2D(tex" << i << ", vec2(0, 0))"; + } + fstrstr << ";\n" + "}\n"; + + mProgram = CompileProgram(vs, fstrstr.str()); + ASSERT_NE(0u, mProgram); + + for (size_t i = 0; i < params.numTextures; ++i) + { + std::stringstream uniformName; + uniformName << "tex" << i; + + GLint location = glGetUniformLocation(mProgram, uniformName.str().c_str()); + ASSERT_NE(-1, location); + mUniformLocations.push_back(location); + } + + // Use the program object + glUseProgram(mProgram); +} + +void TexturesBenchmark::initTextures() +{ + const auto ¶ms = GetParam(); + + size_t textureSize = static_cast<size_t>(1) << params.textureMipCount; + std::vector<GLubyte> textureData(textureSize * textureSize * 4); + for (auto &byte : textureData) + { + byte = rand() % 255u; + } + + for (size_t texIndex = 0; texIndex < params.numTextures; texIndex++) + { + GLuint tex = 0; + glGenTextures(1, &tex); + + glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + texIndex)); + glBindTexture(GL_TEXTURE_2D, tex); + for (size_t mip = 0; mip < params.textureMipCount; mip++) + { + GLsizei levelSize = static_cast<GLsizei>(textureSize >> mip); + glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(mip), GL_RGBA, levelSize, levelSize, 0, + GL_RGBA, GL_UNSIGNED_BYTE, textureData.data()); + } + mTextures.push_back(tex); + + glUniform1i(mUniformLocations[texIndex], static_cast<GLint>(texIndex)); + } +} + +void TexturesBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); +} + +void TexturesBenchmark::drawBenchmark() +{ + const auto ¶ms = GetParam(); + + for (size_t it = 0; it < params.iterations; ++it) + { + if (it % params.textureRebindFrequency == 0) + { + // Swap two textures + size_t swapTexture = (it / params.textureRebindFrequency) % (params.numTextures - 1); + + glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture)); + glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture]); + glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture + 1)); + glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture + 1]); + std::swap(mTextures[swapTexture], mTextures[swapTexture + 1]); + } + + if (it % params.textureStateUpdateFrequency == 0) + { + // Update a texture's state + size_t stateUpdateCount = it / params.textureStateUpdateFrequency; + + const size_t numUpdateTextures = 4; + ASSERT_LE(numUpdateTextures, params.numTextures); + + size_t firstTexture = stateUpdateCount % (params.numTextures - numUpdateTextures); + + for (size_t updateTextureIdx = 0; updateTextureIdx < numUpdateTextures; + updateTextureIdx++) + { + size_t updateTexture = firstTexture + updateTextureIdx; + glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + updateTexture)); + + const GLenum minFilters[] = { + GL_NEAREST, + GL_LINEAR, + GL_NEAREST_MIPMAP_NEAREST, + GL_LINEAR_MIPMAP_NEAREST, + GL_NEAREST_MIPMAP_LINEAR, + GL_LINEAR_MIPMAP_LINEAR, + }; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + minFilters[stateUpdateCount % ArraySize(minFilters)]); + + const GLenum magFilters[] = { + GL_NEAREST, GL_LINEAR, + }; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + magFilters[stateUpdateCount % ArraySize(magFilters)]); + + const GLenum wrapParameters[] = { + GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, + }; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]); + } + } + + glDrawArrays(GL_TRIANGLES, 0, 3); + } + + ASSERT_GL_NO_ERROR(); +} + +TexturesParams D3D11Params() +{ + TexturesParams params; + params.eglParameters = egl_platform::D3D11_NULL(); + return params; +} + +TexturesParams D3D9Params() +{ + TexturesParams params; + params.eglParameters = egl_platform::D3D9_NULL(); + return params; +} + +TexturesParams OpenGLParams() +{ + TexturesParams params; + params.eglParameters = egl_platform::OPENGL_NULL(); + return params; +} + +TEST_P(TexturesBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(TexturesBenchmark, D3D11Params(), D3D9Params(), OpenGLParams()); + +} // namespace angle diff --git a/gfx/angle/src/tests/perf_tests/UniformsPerf.cpp b/gfx/angle/src/tests/perf_tests/UniformsPerf.cpp new file mode 100755 index 000000000..276b1ab9b --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/UniformsPerf.cpp @@ -0,0 +1,228 @@ +// +// Copyright (c) 2016 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. +// +// UniformsBenchmark: +// Performance test for setting uniform data. +// + +#include "ANGLEPerfTest.h" + +#include <iostream> +#include <random> +#include <sstream> + +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +struct UniformsParams final : public RenderTestParams +{ + UniformsParams() + { + // Common default params + majorVersion = 2; + minorVersion = 0; + windowWidth = 720; + windowHeight = 720; + iterations = 4; + + numVertexUniforms = 200; + numFragmentUniforms = 200; + } + + std::string suffix() const override; + size_t numVertexUniforms; + size_t numFragmentUniforms; + + // static parameters + size_t iterations; +}; + +std::ostream &operator<<(std::ostream &os, const UniformsParams ¶ms) +{ + os << params.suffix().substr(1); + return os; +} + +std::string UniformsParams::suffix() const +{ + std::stringstream strstr; + + strstr << RenderTestParams::suffix(); + strstr << "_" << numVertexUniforms << "_vertex_uniforms"; + strstr << "_" << numFragmentUniforms << "_fragment_uniforms"; + + return strstr.str(); +} + +class UniformsBenchmark : public ANGLERenderTest, + public ::testing::WithParamInterface<UniformsParams> +{ + public: + UniformsBenchmark(); + + void initializeBenchmark() override; + void destroyBenchmark() override; + void drawBenchmark() override; + + private: + void initShaders(); + void initVertexBuffer(); + void initTextures(); + + GLuint mProgram; + std::vector<GLuint> mUniformLocations; +}; + +UniformsBenchmark::UniformsBenchmark() : ANGLERenderTest("Uniforms", GetParam()), mProgram(0u) +{ +} + +void UniformsBenchmark::initializeBenchmark() +{ + const auto ¶ms = GetParam(); + + ASSERT_GT(params.iterations, 0u); + + // Verify the uniform counts are within the limits + GLint maxVertexUniforms, maxFragmentUniforms; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxVertexUniforms); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniforms); + + if (params.numVertexUniforms > static_cast<size_t>(maxVertexUniforms)) + { + FAIL() << "Vertex uniform count (" << params.numVertexUniforms << ")" + << " exceeds maximum vertex uniform count: " << maxVertexUniforms << std::endl; + } + if (params.numFragmentUniforms > static_cast<size_t>(maxFragmentUniforms)) + { + FAIL() << "Fragment uniform count (" << params.numFragmentUniforms << ")" + << " exceeds maximum fragment uniform count: " << maxFragmentUniforms << std::endl; + } + + initShaders(); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); + + ASSERT_GL_NO_ERROR(); +} + +std::string GetUniformLocationName(size_t idx, bool vertexShader) +{ + std::stringstream strstr; + strstr << (vertexShader ? "vs" : "fs") << "_u_" << idx; + return strstr.str(); +} + +void UniformsBenchmark::initShaders() +{ + const auto ¶ms = GetParam(); + + std::stringstream vstrstr; + vstrstr << "precision mediump float;\n"; + for (size_t i = 0; i < params.numVertexUniforms; i++) + { + vstrstr << "uniform vec4 " << GetUniformLocationName(i, true) << ";\n"; + } + vstrstr << "void main()\n" + "{\n" + " gl_Position = vec4(0, 0, 0, 0);\n"; + for (size_t i = 0; i < params.numVertexUniforms; i++) + { + vstrstr << " gl_Position = gl_Position + " << GetUniformLocationName(i, true) << ";\n"; + } + vstrstr << "}"; + + std::stringstream fstrstr; + fstrstr << "precision mediump float;\n"; + for (size_t i = 0; i < params.numFragmentUniforms; i++) + { + fstrstr << "uniform vec4 " << GetUniformLocationName(i, false) << ";\n"; + } + fstrstr << "void main()\n" + "{\n" + " gl_FragColor = vec4(0, 0, 0, 0);\n"; + for (size_t i = 0; i < params.numFragmentUniforms; i++) + { + fstrstr << " gl_FragColor = gl_FragColor + " << GetUniformLocationName(i, false) + << ";\n"; + } + fstrstr << "}"; + + mProgram = CompileProgram(vstrstr.str(), fstrstr.str()); + ASSERT_NE(0u, mProgram); + + for (size_t i = 0; i < params.numVertexUniforms; ++i) + { + GLint location = glGetUniformLocation(mProgram, GetUniformLocationName(i, true).c_str()); + ASSERT_NE(-1, location); + mUniformLocations.push_back(location); + } + for (size_t i = 0; i < params.numFragmentUniforms; ++i) + { + GLint location = glGetUniformLocation(mProgram, GetUniformLocationName(i, false).c_str()); + ASSERT_NE(-1, location); + mUniformLocations.push_back(location); + } + + // Use the program object + glUseProgram(mProgram); +} + +void UniformsBenchmark::destroyBenchmark() +{ + glDeleteProgram(mProgram); +} + +void UniformsBenchmark::drawBenchmark() +{ + const auto ¶ms = GetParam(); + + for (size_t it = 0; it < params.iterations; ++it) + { + for (size_t uniform = 0; uniform < mUniformLocations.size(); ++uniform) + { + float value = static_cast<float>(uniform); + glUniform4f(mUniformLocations[uniform], value, value, value, value); + } + + glDrawArrays(GL_TRIANGLES, 0, 3); + } + + ASSERT_GL_NO_ERROR(); +} + +UniformsParams D3D11Params() +{ + UniformsParams params; + params.eglParameters = egl_platform::D3D11(); + return params; +} + +UniformsParams D3D9Params() +{ + UniformsParams params; + params.eglParameters = egl_platform::D3D9(); + return params; +} + +UniformsParams OpenGLParams() +{ + UniformsParams params; + params.eglParameters = egl_platform::OPENGL(); + return params; +} + +} // anonymous namespace + +TEST_P(UniformsBenchmark, Run) +{ + run(); +} + +ANGLE_INSTANTIATE_TEST(UniformsBenchmark, D3D11Params(), D3D9Params(), OpenGLParams()); diff --git a/gfx/angle/src/tests/perf_tests/third_party/perf/angle-mods.patch b/gfx/angle/src/tests/perf_tests/third_party/perf/angle-mods.patch new file mode 100755 index 000000000..d0b640289 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/third_party/perf/angle-mods.patch @@ -0,0 +1,61 @@ +diff --git a/tests/perf_tests/third_party/perf/perf_test.cc b/tests/perf_tests/third_party/perf/perf_test.cc +index 0d5abc0..7364330 100644 +--- a/tests/perf_tests/third_party/perf/perf_test.cc ++++ b/tests/perf_tests/third_party/perf/perf_test.cc +@@ -2,16 +2,51 @@ + // Use of this source code is governed by a BSD-style license that can be + // found in the LICENSE file. + +-#include "testing/perf/perf_test.h" ++#include "perf_test.h" + + #include <stdio.h> +- +-#include "base/logging.h" +-#include "base/strings/string_number_conversions.h" +-#include "base/strings/stringprintf.h" ++#include <stdarg.h> ++#include <vector> + + namespace { + ++namespace base { ++ ++std::string FormatString(const char *fmt, va_list vararg) { ++ static std::vector<char> buffer(512); ++ ++ // Attempt to just print to the current buffer ++ int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg); ++ if (len < 0 || static_cast<size_t>(len) >= buffer.size()) { ++ // Buffer was not large enough, calculate the required size and resize the buffer ++ len = vsnprintf(NULL, 0, fmt, vararg); ++ buffer.resize(len + 1); ++ ++ // Print again ++ vsnprintf(&buffer[0], buffer.size(), fmt, vararg); ++ } ++ ++ return std::string(buffer.data(), len); ++} ++ ++std::string StringPrintf(const char *fmt, ...) { ++ va_list vararg; ++ va_start(vararg, fmt); ++ std::string result = FormatString(fmt, vararg); ++ va_end(vararg); ++ return result; ++} ++ ++std::string UintToString(unsigned int value) { ++ return StringPrintf("%u", value); ++} ++ ++std::string DoubleToString(double value) { ++ return StringPrintf("%.10lf", value); ++} ++ ++} ++ + std::string ResultsToString(const std::string& measurement, + const std::string& modifier, + const std::string& trace, diff --git a/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.cc b/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.cc new file mode 100755 index 000000000..73643306c --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.cc @@ -0,0 +1,239 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "perf_test.h" + +#include <stdio.h> +#include <stdarg.h> +#include <vector> + +namespace { + +namespace base { + +std::string FormatString(const char *fmt, va_list vararg) { + static std::vector<char> buffer(512); + + // Attempt to just print to the current buffer + int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg); + if (len < 0 || static_cast<size_t>(len) >= buffer.size()) { + // Buffer was not large enough, calculate the required size and resize the buffer + len = vsnprintf(NULL, 0, fmt, vararg); + buffer.resize(len + 1); + + // Print again + vsnprintf(&buffer[0], buffer.size(), fmt, vararg); + } + + return std::string(buffer.data(), len); +} + +std::string StringPrintf(const char *fmt, ...) { + va_list vararg; + va_start(vararg, fmt); + std::string result = FormatString(fmt, vararg); + va_end(vararg); + return result; +} + +std::string UintToString(unsigned int value) { + return StringPrintf("%u", value); +} + +std::string DoubleToString(double value) { + return StringPrintf("%.10lf", value); +} + +} + +std::string ResultsToString(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& prefix, + const std::string& suffix, + const std::string& units, + bool important) { + // <*>RESULT <graph_name>: <trace_name>= <value> <units> + // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units> + // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units> + return base::StringPrintf("%sRESULT %s%s: %s= %s%s%s %s\n", + important ? "*" : "", measurement.c_str(), modifier.c_str(), + trace.c_str(), prefix.c_str(), values.c_str(), suffix.c_str(), + units.c_str()); +} + +void PrintResultsImpl(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& prefix, + const std::string& suffix, + const std::string& units, + bool important) { + fflush(stdout); + printf("%s", ResultsToString(measurement, modifier, trace, values, + prefix, suffix, units, important).c_str()); + fflush(stdout); +} + +} // namespace + +namespace perf_test { + +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + size_t value, + const std::string& units, + bool important) { + PrintResultsImpl(measurement, + modifier, + trace, + base::UintToString(static_cast<unsigned int>(value)), + std::string(), + std::string(), + units, + important); +} + +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + double value, + const std::string& units, + bool important) { + PrintResultsImpl(measurement, + modifier, + trace, + base::DoubleToString(value), + std::string(), + std::string(), + units, + important); +} + +void AppendResult(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + size_t value, + const std::string& units, + bool important) { + output += ResultsToString( + measurement, + modifier, + trace, + base::UintToString(static_cast<unsigned int>(value)), + std::string(), + std::string(), + units, + important); +} + +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& value, + const std::string& units, + bool important) { + PrintResultsImpl(measurement, + modifier, + trace, + value, + std::string(), + std::string(), + units, + important); +} + +void AppendResult(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& value, + const std::string& units, + bool important) { + output += ResultsToString(measurement, + modifier, + trace, + value, + std::string(), + std::string(), + units, + important); +} + +void PrintResultMeanAndError(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& mean_and_error, + const std::string& units, + bool important) { + PrintResultsImpl(measurement, modifier, trace, mean_and_error, + "{", "}", units, important); +} + +void AppendResultMeanAndError(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& mean_and_error, + const std::string& units, + bool important) { + output += ResultsToString(measurement, modifier, trace, mean_and_error, + "{", "}", units, important); +} + +void PrintResultList(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& units, + bool important) { + PrintResultsImpl(measurement, modifier, trace, values, + "[", "]", units, important); +} + +void AppendResultList(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& units, + bool important) { + output += ResultsToString(measurement, modifier, trace, values, + "[", "]", units, important); +} + +void PrintSystemCommitCharge(const std::string& test_name, + size_t charge, + bool important) { + PrintSystemCommitCharge(stdout, test_name, charge, important); +} + +void PrintSystemCommitCharge(FILE* target, + const std::string& test_name, + size_t charge, + bool important) { + fprintf(target, "%s", SystemCommitChargeToString(test_name, charge, + important).c_str()); +} + +std::string SystemCommitChargeToString(const std::string& test_name, + size_t charge, + bool important) { + std::string trace_name(test_name); + std::string output; + AppendResult(output, + "commit_charge", + std::string(), + "cc" + trace_name, + charge, + "kb", + important); + return output; +} + +} // namespace perf_test diff --git a/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.h b/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.h new file mode 100755 index 000000000..36e2916c5 --- /dev/null +++ b/gfx/angle/src/tests/perf_tests/third_party/perf/perf_test.h @@ -0,0 +1,116 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TESTING_PERF_PERF_TEST_H_ +#define TESTING_PERF_PERF_TEST_H_ + +#include <string> + +namespace perf_test { + +// Prints numerical information to stdout in a controlled format, for +// post-processing. |measurement| is a description of the quantity being +// measured, e.g. "vm_peak"; |modifier| is provided as a convenience and +// will be appended directly to the name of the |measurement|, e.g. +// "_browser"; |trace| is a description of the particular data point, e.g. +// "reference"; |value| is the measured value; and |units| is a description +// of the units of measure, e.g. "bytes". If |important| is true, the output +// line will be specially marked, to notify the post-processor. The strings +// may be empty. They should not contain any colons (:) or equals signs (=). +// A typical post-processing step would be to produce graphs of the data +// produced for various builds, using the combined |measurement| + |modifier| +// string to specify a particular graph and the |trace| to identify a trace +// (i.e., data series) on that graph. +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + size_t value, + const std::string& units, + bool important); +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + double value, + const std::string& units, + bool important); + +void AppendResult(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + size_t value, + const std::string& units, + bool important); + +// Like the above version of PrintResult(), but takes a std::string value +// instead of a size_t. +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& value, + const std::string& units, + bool important); + +void AppendResult(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& value, + const std::string& units, + bool important); + +// Like PrintResult(), but prints a (mean, standard deviation) result pair. +// The |<values>| should be two comma-separated numbers, the mean and +// standard deviation (or other error metric) of the measurement. +void PrintResultMeanAndError(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& mean_and_error, + const std::string& units, + bool important); + +void AppendResultMeanAndError(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& mean_and_error, + const std::string& units, + bool important); + +// Like PrintResult(), but prints an entire list of results. The |values| +// will generally be a list of comma-separated numbers. A typical +// post-processing step might produce plots of their mean and standard +// deviation. +void PrintResultList(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& units, + bool important); + +void AppendResultList(std::string& output, + const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::string& values, + const std::string& units, + bool important); + +// Prints memory commit charge stats for use by perf graphs. +void PrintSystemCommitCharge(const std::string& test_name, + size_t charge, + bool important); + +void PrintSystemCommitCharge(FILE* target, + const std::string& test_name, + size_t charge, + bool important); + +std::string SystemCommitChargeToString(const std::string& test_name, + size_t charge, + bool important); + +} // namespace perf_test + +#endif // TESTING_PERF_PERF_TEST_H_ |