Commit 07b36365 by Jamie Madill Committed by Commit Bot

D3D11: Don't dirty all uniforms on program change.

Only dirty the uniforms if the uniforms are dirty. This gives about a 20% reduction in ANGLE overhead on a targeted micro-benchmark. It probably won't have that large of an impact on most real-world applications, but it was strictly unnecessary work. Something that came up when investigating the internal program binary cache in ANGLE D3D11. BUG=angleproject:2053 Change-Id: I2d55c010c29ce9627a9001dd2abe6e549f0b7e8c Reviewed-on: https://chromium-review.googlesource.com/524297Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 10bed9fc
......@@ -2429,17 +2429,15 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode
ID3D11VertexShader *vertexShader =
(vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : nullptr);
ID3D11PixelShader *pixelShader = nullptr;
// Skip pixel shader if we're doing rasterizer discard.
bool rasterizerDiscard = glState.getRasterizerState().rasterizerDiscard;
if (!rasterizerDiscard)
ID3D11PixelShader *pixelShader = nullptr;
if (!glState.getRasterizerState().rasterizerDiscard)
{
pixelShader = (pixelExe ? GetAs<ShaderExecutable11>(pixelExe)->getPixelShader() : nullptr);
}
ID3D11GeometryShader *geometryShader = nullptr;
bool transformFeedbackActive = glState.isTransformFeedbackActiveUnpaused();
if (transformFeedbackActive)
if (glState.isTransformFeedbackActiveUnpaused())
{
geometryShader =
(vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getStreamOutShader() : nullptr);
......@@ -2473,11 +2471,6 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode
dirtyUniforms = true;
}
if (dirtyUniforms)
{
programD3D->dirtyAllUniforms();
}
return programD3D->applyUniforms(drawMode);
}
......
......@@ -9,6 +9,7 @@
#include "ANGLEPerfTest.h"
#include <array>
#include <iostream>
#include <random>
#include <sstream>
......@@ -35,6 +36,14 @@ enum DataType
MAT4,
};
// Determines if we state change the program between draws.
// This covers a performance problem in ANGLE where calling UseProgram reuploads uniform data.
enum ProgramMode
{
SINGLE,
MULTIPLE,
};
struct UniformsParams final : public RenderTestParams
{
UniformsParams()
......@@ -52,6 +61,7 @@ struct UniformsParams final : public RenderTestParams
DataType dataType = DataType::VEC4;
DataMode dataMode = DataMode::REPEAT;
ProgramMode programMode = ProgramMode::SINGLE;
// static parameters
size_t iterations = 4;
......@@ -79,6 +89,11 @@ std::string UniformsParams::suffix() const
strstr << "_matrix";
}
if (programMode == ProgramMode::MULTIPLE)
{
strstr << "_multiprogram";
}
if (dataMode == DataMode::REPEAT)
{
strstr << "_repeating";
......@@ -100,9 +115,14 @@ class UniformsBenchmark : public ANGLERenderTest,
private:
void initShaders();
GLuint mProgram;
template <bool MultiProgram, typename SetUniformFunc>
void drawLoop(const SetUniformFunc &setUniformsFunc);
std::array<GLuint, 2> mPrograms;
std::vector<GLuint> mUniformLocations;
std::vector<Matrix4> mMatrixData[2];
using MatrixData = std::array<std::vector<Matrix4>, 2>;
MatrixData mMatrixData;
};
std::vector<Matrix4> GenMatrixData(size_t count, int parity)
......@@ -127,7 +147,7 @@ std::vector<Matrix4> GenMatrixData(size_t count, int parity)
return data;
}
UniformsBenchmark::UniformsBenchmark() : ANGLERenderTest("Uniforms", GetParam()), mProgram(0u)
UniformsBenchmark::UniformsBenchmark() : ANGLERenderTest("Uniforms", GetParam()), mPrograms({})
{
}
......@@ -181,8 +201,9 @@ void UniformsBenchmark::initializeBenchmark()
}
}
GLint attribLocation = glGetAttribLocation(mProgram, "pos");
GLint attribLocation = glGetAttribLocation(mPrograms[0], "pos");
ASSERT_NE(-1, attribLocation);
ASSERT_EQ(attribLocation, glGetAttribLocation(mPrograms[1], "pos"));
glVertexAttrib4f(attribLocation, 1.0f, 0.0f, 0.0f, 1.0f);
ASSERT_GL_NO_ERROR();
......@@ -257,32 +278,41 @@ void UniformsBenchmark::initShaders()
}
fstrstr << "}";
mProgram = CompileProgram(vstrstr.str(), fstrstr.str());
ASSERT_NE(0u, mProgram);
mPrograms[0] = CompileProgram(vstrstr.str(), fstrstr.str());
ASSERT_NE(0u, mPrograms[0]);
mPrograms[1] = CompileProgram(vstrstr.str(), fstrstr.str());
ASSERT_NE(0u, mPrograms[1]);
for (size_t i = 0; i < params.numVertexUniforms; ++i)
{
GLint location = glGetUniformLocation(mProgram, GetUniformLocationName(i, true).c_str());
std::string name = GetUniformLocationName(i, true);
GLint location = glGetUniformLocation(mPrograms[0], name.c_str());
ASSERT_NE(-1, location);
ASSERT_EQ(location, glGetUniformLocation(mPrograms[1], name.c_str()));
mUniformLocations.push_back(location);
}
for (size_t i = 0; i < params.numFragmentUniforms; ++i)
{
GLint location = glGetUniformLocation(mProgram, GetUniformLocationName(i, false).c_str());
std::string name = GetUniformLocationName(i, false);
GLint location = glGetUniformLocation(mPrograms[0], name.c_str());
ASSERT_NE(-1, location);
ASSERT_EQ(location, glGetUniformLocation(mPrograms[1], name.c_str()));
mUniformLocations.push_back(location);
}
// Use the program object
glUseProgram(mProgram);
glUseProgram(mPrograms[0]);
}
void UniformsBenchmark::destroyBenchmark()
{
glDeleteProgram(mProgram);
glDeleteProgram(mPrograms[0]);
glDeleteProgram(mPrograms[1]);
}
void UniformsBenchmark::drawBenchmark()
// Hopefully the compiler is smart enough to inline the lambda setUniformsFunc.
template <bool MultiProgram, typename SetUniformFunc>
void UniformsBenchmark::drawLoop(const SetUniformFunc &setUniformsFunc)
{
const auto &params = GetParam();
......@@ -290,33 +320,66 @@ void UniformsBenchmark::drawBenchmark()
for (size_t it = 0; it < params.iterations; ++it, frameIndex = (frameIndex == 0 ? 1 : 0))
{
for (size_t uniform = 0; uniform < mUniformLocations.size(); ++uniform)
if (MultiProgram)
{
if (params.dataType == DataType::MAT4)
{
glUniformMatrix4fv(mUniformLocations[uniform], 1, GL_FALSE,
mMatrixData[frameIndex][uniform].data);
}
else
glUseProgram(mPrograms[frameIndex]);
}
else
{
for (size_t uniform = 0; uniform < mUniformLocations.size(); ++uniform)
{
float value = static_cast<float>(uniform);
glUniform4f(mUniformLocations[uniform], value, value, value, value);
setUniformsFunc(mUniformLocations, mMatrixData, uniform, frameIndex);
}
}
glDrawArrays(GL_TRIANGLES, 0, 3);
}
}
void UniformsBenchmark::drawBenchmark()
{
const auto &params = GetParam();
if (params.dataType == DataType::MAT4)
{
auto setFunc = [](const std::vector<GLuint> &locations, const MatrixData &matrixData,
size_t uniform, size_t frameIndex) {
glUniformMatrix4fv(locations[uniform], 1, GL_FALSE,
matrixData[frameIndex][uniform].data);
};
drawLoop<false>(setFunc);
}
else
{
auto setFunc = [](const std::vector<GLuint> &locations, const MatrixData &matrixData,
size_t uniform, size_t frameIndex) {
float value = static_cast<float>(uniform);
glUniform4f(locations[uniform], value, value, value, value);
};
if (params.programMode == ProgramMode::MULTIPLE)
{
drawLoop<true>(setFunc);
}
else
{
drawLoop<false>(setFunc);
}
}
ASSERT_GL_NO_ERROR();
}
using namespace egl_platform;
UniformsParams VectorUniforms(const EGLPlatformParameters &egl, DataMode dataMode)
UniformsParams VectorUniforms(const EGLPlatformParameters &egl,
DataMode dataMode,
ProgramMode programMode = ProgramMode::SINGLE)
{
UniformsParams params;
params.eglParameters = egl;
params.dataMode = dataMode;
params.programMode = programMode;
return params;
}
......@@ -350,4 +413,5 @@ ANGLE_INSTANTIATE_TEST(UniformsBenchmark,
MatrixUniforms(D3D11(), DataMode::REPEAT),
MatrixUniforms(D3D11(), DataMode::UPDATE),
MatrixUniforms(OPENGL(), DataMode::REPEAT),
MatrixUniforms(OPENGL(), DataMode::UPDATE));
MatrixUniforms(OPENGL(), DataMode::UPDATE),
VectorUniforms(D3D11_NULL(), DataMode::UPDATE, ProgramMode::MULTIPLE));
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