blob: 2aaf84a01b85ed13a9f478c638e7fee24270e0d4 [file] [log] [blame]
//
// 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.
//
// LinkProgramPerfTest:
// Performance tests compiling a lot of shaders.
//
#include "ANGLEPerfTest.h"
#include <array>
#include "common/vector_utils.h"
#include "util/shader_utils.h"
using namespace angle;
namespace
{
enum class TaskOption
{
CompileOnly,
CompileAndLink,
Unspecified
};
enum class ThreadOption
{
SingleThread,
MultiThread,
Unspecified
};
struct LinkProgramParams final : public RenderTestParams
{
LinkProgramParams(TaskOption taskOptionIn, ThreadOption threadOptionIn)
{
iterationsPerStep = 1;
majorVersion = 2;
minorVersion = 0;
windowWidth = 256;
windowHeight = 256;
taskOption = taskOptionIn;
threadOption = threadOptionIn;
}
std::string story() const override
{
std::stringstream strstr;
strstr << RenderTestParams::story();
if (taskOption == TaskOption::CompileOnly)
{
strstr << "_compile_only";
}
else if (taskOption == TaskOption::CompileAndLink)
{
strstr << "_compile_and_link";
}
if (threadOption == ThreadOption::SingleThread)
{
strstr << "_single_thread";
}
else if (threadOption == ThreadOption::MultiThread)
{
strstr << "_multi_thread";
}
if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
{
strstr << "_null";
}
return strstr.str();
}
TaskOption taskOption;
ThreadOption threadOption;
};
std::ostream &operator<<(std::ostream &os, const LinkProgramParams &params)
{
os << params.backendAndStory().substr(1);
return os;
}
class LinkProgramBenchmark : public ANGLERenderTest,
public ::testing::WithParamInterface<LinkProgramParams>
{
public:
LinkProgramBenchmark();
void initializeBenchmark() override;
void destroyBenchmark() override;
void drawBenchmark() override;
protected:
GLuint mVertexBuffer = 0;
};
LinkProgramBenchmark::LinkProgramBenchmark() : ANGLERenderTest("LinkProgram", GetParam()) {}
void LinkProgramBenchmark::initializeBenchmark()
{
if (GetParam().threadOption != ThreadOption::SingleThread &&
!IsGLExtensionEnabled("GL_KHR_parallel_shader_compile"))
{
skipTest("non-single-thread but missing GL_KHR_parallel_shader_compile");
return;
}
if (IsGLExtensionEnabled("GL_KHR_parallel_shader_compile") &&
GetParam().threadOption == ThreadOption::SingleThread)
{
glMaxShaderCompilerThreadsKHR(0);
}
std::array<Vector3, 6> vertices = {{Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f),
Vector3(1.0f, -1.0f, 0.5f), Vector3(-1.0f, 1.0f, 0.5f),
Vector3(1.0f, -1.0f, 0.5f), Vector3(1.0f, 1.0f, 0.5f)}};
glGenBuffers(1, &mVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vector3), vertices.data(),
GL_STATIC_DRAW);
}
void LinkProgramBenchmark::destroyBenchmark()
{
glDeleteBuffers(1, &mVertexBuffer);
}
void LinkProgramBenchmark::drawBenchmark()
{
static const char *vertexShader =
"attribute vec2 position;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
"}";
static const char *fragmentShader =
"precision mediump float;\n"
"void main() {\n"
" gl_FragColor = vec4(1, 0, 0, 1);\n"
"}";
GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
ASSERT_NE(0u, vs);
ASSERT_NE(0u, fs);
if (GetParam().taskOption == TaskOption::CompileOnly)
{
glDeleteShader(vs);
glDeleteShader(fs);
return;
}
GLuint program = glCreateProgram();
ASSERT_NE(0u, program);
glAttachShader(program, vs);
glDeleteShader(vs);
glAttachShader(program, fs);
glDeleteShader(fs);
glLinkProgram(program);
glUseProgram(program);
GLint positionLoc = glGetAttribLocation(program, "position");
glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
glEnableVertexAttribArray(positionLoc);
// Draw with the program to ensure the shader gets compiled and used.
glDrawArrays(GL_TRIANGLES, 0, 6);
glDeleteProgram(program);
}
using namespace egl_platform;
LinkProgramParams LinkProgramD3D11Params(TaskOption taskOption, ThreadOption threadOption)
{
LinkProgramParams params(taskOption, threadOption);
params.eglParameters = D3D11();
return params;
}
LinkProgramParams LinkProgramOpenGLOrGLESParams(TaskOption taskOption, ThreadOption threadOption)
{
LinkProgramParams params(taskOption, threadOption);
params.eglParameters = OPENGL_OR_GLES();
return params;
}
LinkProgramParams LinkProgramVulkanParams(TaskOption taskOption, ThreadOption threadOption)
{
LinkProgramParams params(taskOption, threadOption);
params.eglParameters = VULKAN();
return params;
}
TEST_P(LinkProgramBenchmark, Run)
{
run();
}
ANGLE_INSTANTIATE_TEST(
LinkProgramBenchmark,
LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::SingleThread),
LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::SingleThread),
LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::SingleThread),
LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::SingleThread));
} // anonymous namespace