ParallelCompile: Parallelize D3D linking
This adds a new linking state to Program. If a Program is in linking
state, on the one hand the foreground thread may continue issuing more
GL calls, and on the other hand the background linking threads may be
accessing Program internally too. Without a proper constraint there
must be conflicts between them. For this purpose, we block any further
GL calls to Program until it's actually linked. In addition, we
prohibit parallel linking an active program, so that ProgramD3D does
not have to worry about such similar conflicts.
Also changes the WorkerThread to support limiting the number of
concurrently running worker threads.
BUG=chromium:849576
Change-Id: I52618647539323f8bf27201320bdf7301c4982e6
Reviewed-on: https://chromium-review.googlesource.com/1127495
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/ParallelShaderCompileTest.cpp b/src/tests/gl_tests/ParallelShaderCompileTest.cpp
index 1117fa5..21788d2 100644
--- a/src/tests/gl_tests/ParallelShaderCompileTest.cpp
+++ b/src/tests/gl_tests/ParallelShaderCompileTest.cpp
@@ -8,6 +8,8 @@
#include "test_utils/ANGLETest.h"
+#include "random_utils.h"
+
using namespace angle;
namespace
@@ -43,6 +45,59 @@
}
return true;
}
+
+ class ClearColorWithDraw
+ {
+ public:
+ ClearColorWithDraw(GLubyte color) : mColor(color, color, color, 255) {}
+
+ bool compileAndLink()
+ {
+ mProgram =
+ CompileProgramParallel(insertRandomString(essl1_shaders::vs::Simple()),
+ insertRandomString(essl1_shaders::fs::UniformColor()));
+ return (mProgram != 0);
+ }
+
+ bool isLinkCompleted()
+ {
+ GLint status;
+ glGetProgramiv(mProgram, GL_COMPLETION_STATUS_KHR, &status);
+ return (status == GL_TRUE);
+ }
+
+ void drawAndVerify(ParallelShaderCompileTest *test)
+ {
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_DEPTH_TEST);
+ glUseProgram(mProgram);
+ ASSERT_GL_NO_ERROR();
+ GLint colorUniformLocation =
+ glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
+ ASSERT_NE(colorUniformLocation, -1);
+ auto normalizeColor = mColor.toNormalizedVector();
+ glUniform4fv(colorUniformLocation, 1, normalizeColor.data());
+ test->drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(test->getWindowWidth() / 2, test->getWindowHeight() / 2, mColor);
+ glUseProgram(0);
+ glDeleteProgram(mProgram);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ private:
+ std::string insertRandomString(const std::string &source)
+ {
+ RNG rng;
+ std::ostringstream ostream;
+ ostream << "// Random string to fool program cache: " << rng.randomInt() << "\n"
+ << source;
+ return ostream.str();
+ }
+
+ GLColor mColor;
+ GLuint mProgram;
+ };
};
// Test basic functionality of GL_KHR_parallel_shader_compile
@@ -58,6 +113,38 @@
EXPECT_EQ(8, count);
}
+// Test to compile and link many programs in parallel.
+TEST_P(ParallelShaderCompileTest, LinkAndDrawManyPrograms)
+{
+ ANGLE_SKIP_TEST_IF(!ensureParallelShaderCompileExtensionAvailable());
+
+ std::vector<std::unique_ptr<ClearColorWithDraw>> tasks;
+ constexpr int kTaskCount = 32;
+ for (int i = 0; i < kTaskCount; ++i)
+ {
+ std::unique_ptr<ClearColorWithDraw> task(new ClearColorWithDraw(i * 255 / kTaskCount));
+ bool isLinking = task->compileAndLink();
+ ASSERT_TRUE(isLinking);
+ tasks.push_back(std::move(task));
+ }
+ constexpr unsigned int kPollInterval = 100;
+ while (!tasks.empty())
+ {
+ for (unsigned int i = 0; i < tasks.size();)
+ {
+ auto &task = tasks[i];
+ if (task->isLinkCompleted())
+ {
+ task->drawAndVerify(this);
+ tasks.erase(tasks.begin() + i);
+ continue;
+ }
+ ++i;
+ }
+ Sleep(kPollInterval);
+ }
+}
+
ANGLE_INSTANTIATE_TEST(ParallelShaderCompileTest,
ES2_D3D9(),
ES2_D3D11(),