Commit cc1dc5ee by Jamie Madill Committed by Commit Bot

Add a perf test for draw calls with texture changes.

This perf test highlights the performance hotspots with State::syncProgramTextures. Also includes a fix to the perf test runner script. Bug: angleproject:2763 Change-Id: I69ffa0cc0d5e023944495b7a1c844770a54f7ddc Reviewed-on: https://chromium-review.googlesource.com/1166041 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 88602e6e
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
# deviation of the population continuously. # deviation of the population continuously.
# #
import glob
import subprocess import subprocess
import sys import sys
import os import os
...@@ -17,15 +18,8 @@ import re ...@@ -17,15 +18,8 @@ import re
base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
# You might have to re-order these to find the specific version you want. # Might have to add lower case "release" in some configurations.
perftests_paths = [ perftests_paths = glob.glob('out/*Release*')
os.path.join('src', 'tests', 'Release_x64'),
os.path.join('src', 'tests', 'Release_Win32'),
os.path.join('out', 'Release_x64'),
os.path.join('out', 'Release'),
os.path.join('gyp', 'Release_x64'),
os.path.join('gyp', 'Release_Win32')
]
metric = 'score' metric = 'score'
binary_name = 'angle_perftests' binary_name = 'angle_perftests'
......
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
namespace namespace
{ {
enum class StateChange
{
NoChange,
VertexBuffer,
Texture,
};
struct DrawArraysPerfParams : public DrawCallPerfParams struct DrawArraysPerfParams : public DrawCallPerfParams
{ {
...@@ -20,7 +26,7 @@ struct DrawArraysPerfParams : public DrawCallPerfParams ...@@ -20,7 +26,7 @@ struct DrawArraysPerfParams : public DrawCallPerfParams
std::string suffix() const override; std::string suffix() const override;
bool changeVertexBuffer = false; StateChange stateChange = StateChange::NoChange;
}; };
std::string DrawArraysPerfParams::suffix() const std::string DrawArraysPerfParams::suffix() const
...@@ -29,9 +35,17 @@ std::string DrawArraysPerfParams::suffix() const ...@@ -29,9 +35,17 @@ std::string DrawArraysPerfParams::suffix() const
strstr << DrawCallPerfParams::suffix(); strstr << DrawCallPerfParams::suffix();
if (changeVertexBuffer) switch (stateChange)
{ {
strstr << "_vbo_change"; case StateChange::VertexBuffer:
strstr << "_vbo_change";
break;
case StateChange::Texture:
strstr << "_tex_change";
break;
default:
break;
;
} }
return strstr.str(); return strstr.str();
...@@ -43,6 +57,36 @@ std::ostream &operator<<(std::ostream &os, const DrawArraysPerfParams &params) ...@@ -43,6 +57,36 @@ std::ostream &operator<<(std::ostream &os, const DrawArraysPerfParams &params)
return os; return os;
} }
GLuint CreateSimpleTexture2D()
{
// 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);
// Load the texture: 2x2 Image, 3 bytes per pixel (R, G, B)
constexpr size_t width = 2;
constexpr size_t height = 2;
GLubyte pixels[width * height * 3] = {
255, 0, 0, // Red
0, 255, 0, // Green
0, 0, 255, // Blue
255, 255, 0, // Yellow
};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// 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;
}
class DrawCallPerfBenchmark : public ANGLERenderTest, class DrawCallPerfBenchmark : public ANGLERenderTest,
public ::testing::WithParamInterface<DrawArraysPerfParams> public ::testing::WithParamInterface<DrawArraysPerfParams>
{ {
...@@ -58,7 +102,9 @@ class DrawCallPerfBenchmark : public ANGLERenderTest, ...@@ -58,7 +102,9 @@ class DrawCallPerfBenchmark : public ANGLERenderTest,
GLuint mBuffer1 = 0; GLuint mBuffer1 = 0;
GLuint mBuffer2 = 0; GLuint mBuffer2 = 0;
GLuint mFBO = 0; GLuint mFBO = 0;
GLuint mTexture = 0; GLuint mFBOTexture = 0;
GLuint mTexture1 = 0;
GLuint mTexture2 = 0;
int mNumTris = GetParam().numTris; int mNumTris = GetParam().numTris;
}; };
...@@ -73,7 +119,15 @@ void DrawCallPerfBenchmark::initializeBenchmark() ...@@ -73,7 +119,15 @@ void DrawCallPerfBenchmark::initializeBenchmark()
ASSERT_LT(0u, params.iterations); ASSERT_LT(0u, params.iterations);
mProgram = SetupSimpleDrawProgram(); if (params.stateChange == StateChange::Texture)
{
mProgram = SetupSimpleTextureProgram();
}
else
{
mProgram = SetupSimpleDrawProgram();
}
ASSERT_NE(0u, mProgram); ASSERT_NE(0u, mProgram);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
...@@ -89,9 +143,12 @@ void DrawCallPerfBenchmark::initializeBenchmark() ...@@ -89,9 +143,12 @@ void DrawCallPerfBenchmark::initializeBenchmark()
if (params.useFBO) if (params.useFBO)
{ {
CreateColorFBO(getWindow()->getWidth(), getWindow()->getHeight(), &mTexture, &mFBO); CreateColorFBO(getWindow()->getWidth(), getWindow()->getHeight(), &mFBOTexture, &mFBO);
} }
mTexture1 = CreateSimpleTexture2D();
mTexture2 = CreateSimpleTexture2D();
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -100,7 +157,9 @@ void DrawCallPerfBenchmark::destroyBenchmark() ...@@ -100,7 +157,9 @@ void DrawCallPerfBenchmark::destroyBenchmark()
glDeleteProgram(mProgram); glDeleteProgram(mProgram);
glDeleteBuffers(1, &mBuffer1); glDeleteBuffers(1, &mBuffer1);
glDeleteBuffers(1, &mBuffer2); glDeleteBuffers(1, &mBuffer2);
glDeleteTextures(1, &mTexture); glDeleteTextures(1, &mFBOTexture);
glDeleteTextures(1, &mTexture1);
glDeleteTextures(1, &mTexture2);
glDeleteFramebuffers(1, &mFBO); glDeleteFramebuffers(1, &mFBO);
} }
...@@ -139,6 +198,21 @@ void ChangeVerticesThenDraw(unsigned int iterations, ...@@ -139,6 +198,21 @@ void ChangeVerticesThenDraw(unsigned int iterations,
} }
} }
void ChangeTextureThenDraw(unsigned int iterations,
GLsizei numElements,
GLuint texture1,
GLuint texture2)
{
for (unsigned int it = 0; it < iterations; it++)
{
glBindTexture(GL_TEXTURE_2D, texture1);
glDrawArrays(GL_TRIANGLES, 0, numElements);
glBindTexture(GL_TEXTURE_2D, texture2);
glDrawArrays(GL_TRIANGLES, 0, numElements);
}
}
void DrawCallPerfBenchmark::drawBenchmark() void DrawCallPerfBenchmark::drawBenchmark()
{ {
// This workaround fixes a huge queue of graphics commands accumulating on the GL // This workaround fixes a huge queue of graphics commands accumulating on the GL
...@@ -148,19 +222,26 @@ void DrawCallPerfBenchmark::drawBenchmark() ...@@ -148,19 +222,26 @@ void DrawCallPerfBenchmark::drawBenchmark()
const auto &params = GetParam(); const auto &params = GetParam();
GLsizei numElements = static_cast<GLsizei>(3 * mNumTris); GLsizei numElements = static_cast<GLsizei>(3 * mNumTris);
if (params.changeVertexBuffer) switch (params.stateChange)
{ {
ChangeVerticesThenDraw(params.iterations, numElements, mBuffer1, mBuffer2); case StateChange::VertexBuffer:
} ChangeVerticesThenDraw(params.iterations, numElements, mBuffer1, mBuffer2);
else if (eglParams.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE || break;
(eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE && case StateChange::Texture:
eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) ChangeTextureThenDraw(params.iterations, numElements, mTexture1, mTexture2);
{ break;
ClearThenDraw(params.iterations, numElements); case StateChange::NoChange:
} if (eglParams.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE ||
else (eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE &&
{ eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE))
JustDraw(params.iterations, numElements); {
ClearThenDraw(params.iterations, numElements);
}
else
{
JustDraw(params.iterations, numElements);
}
break;
} }
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -171,29 +252,33 @@ TEST_P(DrawCallPerfBenchmark, Run) ...@@ -171,29 +252,33 @@ TEST_P(DrawCallPerfBenchmark, Run)
run(); run();
} }
DrawArraysPerfParams DrawArrays(const DrawCallPerfParams &base, bool withBufferChange) DrawArraysPerfParams DrawArrays(const DrawCallPerfParams &base, StateChange stateChange)
{ {
DrawArraysPerfParams params(base); DrawArraysPerfParams params(base);
params.changeVertexBuffer = withBufferChange; params.stateChange = stateChange;
return params; return params;
} }
ANGLE_INSTANTIATE_TEST(DrawCallPerfBenchmark, ANGLE_INSTANTIATE_TEST(
DrawArrays(DrawCallPerfD3D9Params(false, false), false), DrawCallPerfBenchmark,
DrawArrays(DrawCallPerfD3D9Params(true, false), false), DrawArrays(DrawCallPerfD3D9Params(false, false), StateChange::NoChange),
DrawArrays(DrawCallPerfD3D11Params(false, false), false), DrawArrays(DrawCallPerfD3D9Params(true, false), StateChange::NoChange),
DrawArrays(DrawCallPerfD3D11Params(true, false), false), DrawArrays(DrawCallPerfD3D11Params(false, false), StateChange::NoChange),
DrawArrays(DrawCallPerfD3D11Params(true, true), false), DrawArrays(DrawCallPerfD3D11Params(true, false), StateChange::NoChange),
DrawArrays(DrawCallPerfD3D11Params(false, false), true), DrawArrays(DrawCallPerfD3D11Params(true, true), StateChange::NoChange),
DrawArrays(DrawCallPerfD3D11Params(true, false), true), DrawArrays(DrawCallPerfD3D11Params(false, false), StateChange::VertexBuffer),
DrawArrays(DrawCallPerfOpenGLOrGLESParams(false, false), false), DrawArrays(DrawCallPerfD3D11Params(true, false), StateChange::VertexBuffer),
DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, false), false), DrawArrays(DrawCallPerfD3D11Params(true, false), StateChange::Texture),
DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, true), false), DrawArrays(DrawCallPerfOpenGLOrGLESParams(false, false), StateChange::NoChange),
DrawArrays(DrawCallPerfOpenGLOrGLESParams(false, false), true), DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, false), StateChange::NoChange),
DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, false), true), DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, true), StateChange::NoChange),
DrawArrays(DrawCallPerfValidationOnly(), false), DrawArrays(DrawCallPerfOpenGLOrGLESParams(false, false), StateChange::VertexBuffer),
DrawArrays(DrawCallPerfVulkanParams(true, false), true), DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, false), StateChange::VertexBuffer),
DrawArrays(DrawCallPerfVulkanParams(true, false), false), DrawArrays(DrawCallPerfOpenGLOrGLESParams(true, false), StateChange::Texture),
DrawArrays(DrawCallPerfVulkanParams(false, false), false), DrawArrays(DrawCallPerfValidationOnly(), StateChange::NoChange),
DrawArrays(DrawCallPerfVulkanParams(false, false), true)); DrawArrays(DrawCallPerfVulkanParams(true, false), StateChange::VertexBuffer),
DrawArrays(DrawCallPerfVulkanParams(true, false), StateChange::NoChange),
DrawArrays(DrawCallPerfVulkanParams(false, false), StateChange::NoChange),
DrawArrays(DrawCallPerfVulkanParams(false, false), StateChange::VertexBuffer));
} // namespace } // namespace
...@@ -41,6 +41,17 @@ const char *SimpleDrawVertexShaderSource() ...@@ -41,6 +41,17 @@ const char *SimpleDrawVertexShaderSource()
})"; })";
} }
const char *SimpleTexCoordVertexShaderSource()
{
return R"(attribute vec2 vPosition;
varying vec2 texCoord;
void main()
{
gl_Position = vec4(vPosition, 0, 1);
texCoord = vPosition * 0.5 + vec2(0.5);
})";
}
const char *SimpleFragmentShaderSource() const char *SimpleFragmentShaderSource()
{ {
return return
...@@ -51,6 +62,17 @@ const char *SimpleFragmentShaderSource() ...@@ -51,6 +62,17 @@ const char *SimpleFragmentShaderSource()
})"; })";
} }
const char *SimpleTextureFragmentShaderSource()
{
return R"(precision mediump float;
varying vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
})";
}
void Generate2DTriangleData(size_t numTris, std::vector<float> *floatData) void Generate2DTriangleData(size_t numTris, std::vector<float> *floatData)
{ {
for (size_t triIndex = 0; triIndex < numTris; ++triIndex) for (size_t triIndex = 0; triIndex < numTris; ++triIndex)
...@@ -105,6 +127,22 @@ GLuint SetupSimpleDrawProgram() ...@@ -105,6 +127,22 @@ GLuint SetupSimpleDrawProgram()
return program; return program;
} }
GLuint SetupSimpleTextureProgram()
{
const std::string vs = SimpleTexCoordVertexShaderSource();
const std::string fs = SimpleTextureFragmentShaderSource();
GLuint program = CompileProgram(vs, fs);
if (program == 0u)
{
return program;
}
// Use the program object
glUseProgram(program);
return program;
}
GLuint Create2DTriangleBuffer(size_t numTris, GLenum usage) GLuint Create2DTriangleBuffer(size_t numTris, GLenum usage)
{ {
GLuint buffer = 0u; GLuint buffer = 0u;
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
// Returns program ID. The program is left in use, no uniforms. // Returns program ID. The program is left in use, no uniforms.
GLuint SetupSimpleDrawProgram(); GLuint SetupSimpleDrawProgram();
// Returns program ID. Uses a 2D texture.
GLuint SetupSimpleTextureProgram();
// Returns program ID. The program is left in use and the uniforms are set to default values: // Returns program ID. The program is left in use and the uniforms are set to default values:
// uScale = 0.5, uOffset = -0.5 // uScale = 0.5, uOffset = -0.5
GLuint SetupSimpleScaleAndOffsetProgram(); GLuint SetupSimpleScaleAndOffsetProgram();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment