Vulkan: Add a perf test for pre-rotation code injection

A test is added that dispatches a large number of vertex shaders,
generating primitives that are all culled.  The vertex shaders are
simple so that code injected for pre-rotation would make up the majority
of the shader code.

Bug: angleproject:5478
Change-Id: I75092cb25e6427449251985f56e54f89813dec32
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2615821
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Shahbaz Youssefi 2021-01-07 16:46:54 -05:00 коммит произвёл Commit Bot
Родитель 2aa4f7e521
Коммит 7cdda2dc5f
2 изменённых файлов: 212 добавлений и 0 удалений

Просмотреть файл

@ -20,6 +20,7 @@ angle_perf_tests_sources = [
"perf_tests/MultisampledRenderToTexturePerf.cpp",
"perf_tests/MultiviewPerf.cpp",
"perf_tests/PointSprites.cpp",
"perf_tests/PreRotationPerf.cpp",
"perf_tests/TextureSampling.cpp",
"perf_tests/TextureUploadPerf.cpp",
"perf_tests/TexturesPerf.cpp",

Просмотреть файл

@ -0,0 +1,211 @@
//
// Copyright 2020 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.
//
// PreRotationBenchmark:
// Performance test for pre-rotation code generation.
//
#include "ANGLEPerfTest.h"
#include <iostream>
#include <random>
#include <sstream>
#include "test_utils/gl_raii.h"
#include "util/shader_utils.h"
using namespace angle;
namespace
{
constexpr unsigned int kIterationsPerStep = 20;
enum class PreRotation
{
_0,
_90,
_180,
_270,
};
struct PreRotationParams final : public RenderTestParams
{
PreRotationParams()
{
iterationsPerStep = kIterationsPerStep;
trackGpuTime = true;
preRotation = PreRotation::_0;
}
std::string story() const override;
PreRotation preRotation;
};
std::ostream &operator<<(std::ostream &os, const PreRotationParams &params)
{
return os << params.backendAndStory().substr(1);
}
std::string PreRotationParams::story() const
{
std::stringstream strstr;
strstr << RenderTestParams::story();
switch (preRotation)
{
case PreRotation::_0:
strstr << "_NoPreRotation";
break;
case PreRotation::_90:
strstr << "_PreRotate90";
break;
case PreRotation::_180:
strstr << "_PreRotate180";
break;
case PreRotation::_270:
strstr << "_PreRotate270";
break;
}
return strstr.str();
}
class PreRotationBenchmark : public ANGLERenderTest,
public ::testing::WithParamInterface<PreRotationParams>
{
public:
PreRotationBenchmark();
void initializeBenchmark() override;
void destroyBenchmark() override;
void drawBenchmark() override;
protected:
GLuint mProgram = 0;
};
PreRotationBenchmark::PreRotationBenchmark() : ANGLERenderTest("PreRotation", GetParam()) {}
void PreRotationBenchmark::initializeBenchmark()
{
constexpr char kVS[] = R"(
attribute mediump vec4 positionIn;
void main()
{
gl_Position = positionIn;
})";
constexpr char kFS[] = R"(precision mediump float;
void main()
{
gl_FragColor = vec4(0);
})";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
ASSERT_GL_NO_ERROR();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
// Perform a draw so everything is flushed.
glDrawArrays(GL_TRIANGLES, 0, 3);
ASSERT_GL_NO_ERROR();
}
void PreRotationBenchmark::destroyBenchmark()
{
glDeleteProgram(mProgram);
}
void PreRotationBenchmark::drawBenchmark()
{
const auto &params = GetParam();
constexpr uint32_t kDrawCallSize = 100'000;
GLint attribLocation = glGetAttribLocation(mProgram, "positionIn");
ASSERT_NE(-1, attribLocation);
startGpuTimer();
for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
{
// Set the position attribute such that every generated primitive is out of bounds and is
// clipped. This means the test is spending its time almost entirely with vertex shaders.
// The vertex shader itself is simple so that any code that is added for pre-rotation will
// contribute a comparably sizable chunk of code.
switch (iteration % 5)
{
case 0:
glVertexAttrib4f(attribLocation, -2.0f, 0.0f, 0.0f, 1.0f);
break;
case 1:
glVertexAttrib4f(attribLocation, 2.0f, 0.0f, 0.0f, 1.0f);
break;
case 2:
glVertexAttrib4f(attribLocation, 0.0f, -2.0f, 0.0f, 1.0f);
break;
case 3:
glVertexAttrib4f(attribLocation, 0.0f, 2.0f, 0.0f, 1.0f);
break;
case 4:
glVertexAttrib4f(attribLocation, 0.0f, 0.0f, -2.0f, 1.0f);
break;
}
// Draw many points, all which are culled.
glDrawArrays(GL_POINTS, 0, kDrawCallSize);
}
stopGpuTimer();
ASSERT_GL_NO_ERROR();
}
PreRotationParams VulkanParams(PreRotation preRotation)
{
PreRotationParams params;
params.eglParameters = egl_platform::VULKAN();
params.preRotation = preRotation;
switch (preRotation)
{
case PreRotation::_0:
break;
case PreRotation::_90:
params.eglParameters.emulatedPrerotation = 90;
break;
case PreRotation::_180:
params.eglParameters.emulatedPrerotation = 180;
break;
case PreRotation::_270:
params.eglParameters.emulatedPrerotation = 270;
break;
}
return params;
}
} // anonymous namespace
TEST_P(PreRotationBenchmark, Run)
{
run();
}
using namespace params;
ANGLE_INSTANTIATE_TEST(PreRotationBenchmark,
VulkanParams(PreRotation::_0),
VulkanParams(PreRotation::_90),
VulkanParams(PreRotation::_180),
VulkanParams(PreRotation::_270));