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 ...@@ -2429,17 +2429,15 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode
ID3D11VertexShader *vertexShader = ID3D11VertexShader *vertexShader =
(vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : nullptr); (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : nullptr);
ID3D11PixelShader *pixelShader = nullptr;
// Skip pixel shader if we're doing rasterizer discard. // Skip pixel shader if we're doing rasterizer discard.
bool rasterizerDiscard = glState.getRasterizerState().rasterizerDiscard; ID3D11PixelShader *pixelShader = nullptr;
if (!rasterizerDiscard) if (!glState.getRasterizerState().rasterizerDiscard)
{ {
pixelShader = (pixelExe ? GetAs<ShaderExecutable11>(pixelExe)->getPixelShader() : nullptr); pixelShader = (pixelExe ? GetAs<ShaderExecutable11>(pixelExe)->getPixelShader() : nullptr);
} }
ID3D11GeometryShader *geometryShader = nullptr; ID3D11GeometryShader *geometryShader = nullptr;
bool transformFeedbackActive = glState.isTransformFeedbackActiveUnpaused(); if (glState.isTransformFeedbackActiveUnpaused())
if (transformFeedbackActive)
{ {
geometryShader = geometryShader =
(vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getStreamOutShader() : nullptr); (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getStreamOutShader() : nullptr);
...@@ -2473,11 +2471,6 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode ...@@ -2473,11 +2471,6 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode
dirtyUniforms = true; dirtyUniforms = true;
} }
if (dirtyUniforms)
{
programD3D->dirtyAllUniforms();
}
return programD3D->applyUniforms(drawMode); return programD3D->applyUniforms(drawMode);
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ANGLEPerfTest.h" #include "ANGLEPerfTest.h"
#include <array>
#include <iostream> #include <iostream>
#include <random> #include <random>
#include <sstream> #include <sstream>
...@@ -35,6 +36,14 @@ enum DataType ...@@ -35,6 +36,14 @@ enum DataType
MAT4, 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 struct UniformsParams final : public RenderTestParams
{ {
UniformsParams() UniformsParams()
...@@ -52,6 +61,7 @@ struct UniformsParams final : public RenderTestParams ...@@ -52,6 +61,7 @@ struct UniformsParams final : public RenderTestParams
DataType dataType = DataType::VEC4; DataType dataType = DataType::VEC4;
DataMode dataMode = DataMode::REPEAT; DataMode dataMode = DataMode::REPEAT;
ProgramMode programMode = ProgramMode::SINGLE;
// static parameters // static parameters
size_t iterations = 4; size_t iterations = 4;
...@@ -79,6 +89,11 @@ std::string UniformsParams::suffix() const ...@@ -79,6 +89,11 @@ std::string UniformsParams::suffix() const
strstr << "_matrix"; strstr << "_matrix";
} }
if (programMode == ProgramMode::MULTIPLE)
{
strstr << "_multiprogram";
}
if (dataMode == DataMode::REPEAT) if (dataMode == DataMode::REPEAT)
{ {
strstr << "_repeating"; strstr << "_repeating";
...@@ -100,9 +115,14 @@ class UniformsBenchmark : public ANGLERenderTest, ...@@ -100,9 +115,14 @@ class UniformsBenchmark : public ANGLERenderTest,
private: private:
void initShaders(); 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<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) std::vector<Matrix4> GenMatrixData(size_t count, int parity)
...@@ -127,7 +147,7 @@ std::vector<Matrix4> GenMatrixData(size_t count, int parity) ...@@ -127,7 +147,7 @@ std::vector<Matrix4> GenMatrixData(size_t count, int parity)
return data; return data;
} }
UniformsBenchmark::UniformsBenchmark() : ANGLERenderTest("Uniforms", GetParam()), mProgram(0u) UniformsBenchmark::UniformsBenchmark() : ANGLERenderTest("Uniforms", GetParam()), mPrograms({})
{ {
} }
...@@ -181,8 +201,9 @@ void UniformsBenchmark::initializeBenchmark() ...@@ -181,8 +201,9 @@ void UniformsBenchmark::initializeBenchmark()
} }
} }
GLint attribLocation = glGetAttribLocation(mProgram, "pos"); GLint attribLocation = glGetAttribLocation(mPrograms[0], "pos");
ASSERT_NE(-1, attribLocation); ASSERT_NE(-1, attribLocation);
ASSERT_EQ(attribLocation, glGetAttribLocation(mPrograms[1], "pos"));
glVertexAttrib4f(attribLocation, 1.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f(attribLocation, 1.0f, 0.0f, 0.0f, 1.0f);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -257,32 +278,41 @@ void UniformsBenchmark::initShaders() ...@@ -257,32 +278,41 @@ void UniformsBenchmark::initShaders()
} }
fstrstr << "}"; fstrstr << "}";
mProgram = CompileProgram(vstrstr.str(), fstrstr.str()); mPrograms[0] = CompileProgram(vstrstr.str(), fstrstr.str());
ASSERT_NE(0u, mProgram); 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) 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_NE(-1, location);
ASSERT_EQ(location, glGetUniformLocation(mPrograms[1], name.c_str()));
mUniformLocations.push_back(location); mUniformLocations.push_back(location);
} }
for (size_t i = 0; i < params.numFragmentUniforms; ++i) 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_NE(-1, location);
ASSERT_EQ(location, glGetUniformLocation(mPrograms[1], name.c_str()));
mUniformLocations.push_back(location); mUniformLocations.push_back(location);
} }
// Use the program object // Use the program object
glUseProgram(mProgram); glUseProgram(mPrograms[0]);
} }
void UniformsBenchmark::destroyBenchmark() 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(); const auto &params = GetParam();
...@@ -290,33 +320,66 @@ void UniformsBenchmark::drawBenchmark() ...@@ -290,33 +320,66 @@ void UniformsBenchmark::drawBenchmark()
for (size_t it = 0; it < params.iterations; ++it, frameIndex = (frameIndex == 0 ? 1 : 0)) 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) glUseProgram(mPrograms[frameIndex]);
{ }
glUniformMatrix4fv(mUniformLocations[uniform], 1, GL_FALSE, else
mMatrixData[frameIndex][uniform].data); {
} for (size_t uniform = 0; uniform < mUniformLocations.size(); ++uniform)
else
{ {
float value = static_cast<float>(uniform); setUniformsFunc(mUniformLocations, mMatrixData, uniform, frameIndex);
glUniform4f(mUniformLocations[uniform], value, value, value, value);
} }
} }
glDrawArrays(GL_TRIANGLES, 0, 3); 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(); ASSERT_GL_NO_ERROR();
} }
using namespace egl_platform; using namespace egl_platform;
UniformsParams VectorUniforms(const EGLPlatformParameters &egl, DataMode dataMode) UniformsParams VectorUniforms(const EGLPlatformParameters &egl,
DataMode dataMode,
ProgramMode programMode = ProgramMode::SINGLE)
{ {
UniformsParams params; UniformsParams params;
params.eglParameters = egl; params.eglParameters = egl;
params.dataMode = dataMode; params.dataMode = dataMode;
params.programMode = programMode;
return params; return params;
} }
...@@ -350,4 +413,5 @@ ANGLE_INSTANTIATE_TEST(UniformsBenchmark, ...@@ -350,4 +413,5 @@ ANGLE_INSTANTIATE_TEST(UniformsBenchmark,
MatrixUniforms(D3D11(), DataMode::REPEAT), MatrixUniforms(D3D11(), DataMode::REPEAT),
MatrixUniforms(D3D11(), DataMode::UPDATE), MatrixUniforms(D3D11(), DataMode::UPDATE),
MatrixUniforms(OPENGL(), DataMode::REPEAT), 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