ParallelCompile: Parallelize shader translation
This changes to construct a new ShHandle of compiler for each Shader,
and use it to translate the shader source in a background thread.
Bug: chromium:849576
Change-Id: Ib49952c7292321ee6aa1c5996f8f7927f40d8f04
Reviewed-on: https://chromium-review.googlesource.com/1177195
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Compiler.cpp b/src/libANGLE/Compiler.cpp
index 9540651..7cf4b34 100644
--- a/src/libANGLE/Compiler.cpp
+++ b/src/libANGLE/Compiler.cpp
@@ -19,9 +19,8 @@
namespace
{
-// Global count of active shader compiler handles. Needed to know when to call sh::Initialize and
-// sh::Finalize.
-size_t activeCompilerHandles = 0;
+// To know when to call sh::Initialize and sh::Finalize.
+size_t gActiveCompilers = 0;
ShShaderSpec SelectShaderSpec(GLint majorVersion, GLint minorVersion, bool isWebGL)
{
@@ -54,8 +53,7 @@
state.getClientMinorVersion(),
state.getExtensions().webglCompatibility)),
mOutputType(mImplementation->getTranslatorOutputType()),
- mResources(),
- mShaderCompilers({})
+ mResources()
{
ASSERT(state.getClientMajorVersion() == 1 || state.getClientMajorVersion() == 2 ||
state.getClientMajorVersion() == 3);
@@ -63,6 +61,12 @@
const gl::Caps &caps = state.getCaps();
const gl::Extensions &extensions = state.getExtensions();
+ if (gActiveCompilers == 0)
+ {
+ sh::Initialize();
+ }
+ ++gActiveCompilers;
+
sh::InitBuiltInResources(&mResources);
mResources.MaxVertexAttribs = caps.maxVertexAttributes;
mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors;
@@ -161,50 +165,111 @@
Compiler::~Compiler()
{
- for (ShaderType shaderType : AllShaderTypes())
+ for (auto &pool : mPools)
{
- ShHandle compilerHandle = mShaderCompilers[shaderType];
- if (compilerHandle)
+ for (ShCompilerInstance &instance : pool)
{
- sh::Destruct(compilerHandle);
- mShaderCompilers[shaderType] = nullptr;
-
- ASSERT(activeCompilerHandles > 0);
- activeCompilerHandles--;
+ instance.destroy();
}
}
-
- if (activeCompilerHandles == 0)
+ --gActiveCompilers;
+ if (gActiveCompilers == 0)
{
sh::Finalize();
}
-
ANGLE_SWALLOW_ERR(mImplementation->release());
}
-ShHandle Compiler::getCompilerHandle(ShaderType type)
+ShCompilerInstance Compiler::getInstance(ShaderType type)
{
ASSERT(type != ShaderType::InvalidEnum);
- ShHandle *compiler = &mShaderCompilers[type];
-
- if (!(*compiler))
+ auto &pool = mPools[type];
+ if (pool.empty())
{
- if (activeCompilerHandles == 0)
- {
- sh::Initialize();
- }
-
- *compiler = sh::ConstructCompiler(ToGLenum(type), mSpec, mOutputType, &mResources);
- ASSERT(*compiler);
- activeCompilerHandles++;
+ ShHandle handle = sh::ConstructCompiler(ToGLenum(type), mSpec, mOutputType, &mResources);
+ ASSERT(handle);
+ return ShCompilerInstance(handle, mOutputType, type);
}
-
- return *compiler;
+ else
+ {
+ ShCompilerInstance instance = std::move(pool.back());
+ pool.pop_back();
+ return instance;
+ }
}
-const std::string &Compiler::getBuiltinResourcesString(ShaderType type)
+void Compiler::putInstance(ShCompilerInstance &&instance)
{
- return sh::GetBuiltInResourcesString(getCompilerHandle(type));
+ static constexpr size_t kMaxPoolSize = 32;
+ auto &pool = mPools[instance.getShaderType()];
+ if (pool.size() < kMaxPoolSize)
+ {
+ pool.push_back(std::move(instance));
+ }
+ else
+ {
+ instance.destroy();
+ }
+}
+
+ShCompilerInstance::ShCompilerInstance() : mHandle(nullptr)
+{
+}
+
+ShCompilerInstance::ShCompilerInstance(ShHandle handle,
+ ShShaderOutput outputType,
+ ShaderType shaderType)
+ : mHandle(handle), mOutputType(outputType), mShaderType(shaderType)
+{
+}
+
+ShCompilerInstance::~ShCompilerInstance()
+{
+ ASSERT(mHandle == nullptr);
+}
+
+void ShCompilerInstance::destroy()
+{
+ if (mHandle != nullptr)
+ {
+ sh::Destruct(mHandle);
+ mHandle = nullptr;
+ }
+}
+
+ShCompilerInstance::ShCompilerInstance(ShCompilerInstance &&other)
+ : mHandle(other.mHandle), mOutputType(other.mOutputType), mShaderType(other.mShaderType)
+{
+ other.mHandle = nullptr;
+}
+
+ShCompilerInstance &ShCompilerInstance::operator=(ShCompilerInstance &&other)
+{
+ mHandle = other.mHandle;
+ mOutputType = other.mOutputType;
+ mShaderType = other.mShaderType;
+ other.mHandle = nullptr;
+ return *this;
+}
+
+ShHandle ShCompilerInstance::getHandle()
+{
+ return mHandle;
+}
+
+ShaderType ShCompilerInstance::getShaderType() const
+{
+ return mShaderType;
+}
+
+const std::string &ShCompilerInstance::getBuiltinResourcesString()
+{
+ return sh::GetBuiltInResourcesString(mHandle);
+}
+
+ShShaderOutput ShCompilerInstance::getShaderOutputType() const
+{
+ return mOutputType;
}
} // namespace gl
diff --git a/src/libANGLE/Compiler.h b/src/libANGLE/Compiler.h
index 6c0401a..aa0b277 100644
--- a/src/libANGLE/Compiler.h
+++ b/src/libANGLE/Compiler.h
@@ -10,6 +10,8 @@
#ifndef LIBANGLE_COMPILER_H_
#define LIBANGLE_COMPILER_H_
+#include <vector>
+
#include "GLSLANG/ShaderLang.h"
#include "common/PackedEnums.h"
#include "libANGLE/Error.h"
@@ -24,15 +26,16 @@
namespace gl
{
class ContextState;
+class ShCompilerInstance;
class Compiler final : public RefCountObjectNoID
{
public:
Compiler(rx::GLImplFactory *implFactory, const ContextState &data);
- ShHandle getCompilerHandle(ShaderType shaderType);
+ ShCompilerInstance getInstance(ShaderType shaderType);
+ void putInstance(ShCompilerInstance &&instance);
ShShaderOutput getShaderOutputType() const { return mOutputType; }
- const std::string &getBuiltinResourcesString(ShaderType type);
private:
~Compiler() override;
@@ -40,8 +43,29 @@
ShShaderSpec mSpec;
ShShaderOutput mOutputType;
ShBuiltInResources mResources;
+ ShaderMap<std::vector<ShCompilerInstance>> mPools;
+};
- ShaderMap<ShHandle> mShaderCompilers;
+class ShCompilerInstance final : public angle::NonCopyable
+{
+ public:
+ ShCompilerInstance();
+ ShCompilerInstance(ShHandle handle, ShShaderOutput outputType, ShaderType shaderType);
+ ~ShCompilerInstance();
+ void destroy();
+
+ ShCompilerInstance(ShCompilerInstance &&other);
+ ShCompilerInstance &operator=(ShCompilerInstance &&other);
+
+ ShHandle getHandle();
+ ShaderType getShaderType() const;
+ const std::string &getBuiltinResourcesString();
+ ShShaderOutput getShaderOutputType() const;
+
+ private:
+ ShHandle mHandle;
+ ShShaderOutput mOutputType;
+ ShaderType mShaderType;
};
} // namespace gl
diff --git a/src/libANGLE/Shader.cpp b/src/libANGLE/Shader.cpp
index a2697da..3ebcab2 100644
--- a/src/libANGLE/Shader.cpp
+++ b/src/libANGLE/Shader.cpp
@@ -10,6 +10,7 @@
#include "libANGLE/Shader.h"
+#include <functional>
#include <sstream>
#include "GLSLANG/ShaderLang.h"
@@ -19,6 +20,7 @@
#include "libANGLE/Constants.h"
#include "libANGLE/Context.h"
#include "libANGLE/ResourceManager.h"
+#include "libANGLE/WorkerThread.h"
#include "libANGLE/renderer/GLImplFactory.h"
#include "libANGLE/renderer/ShaderImpl.h"
@@ -96,6 +98,50 @@
}
}
+class ScopedExit final : angle::NonCopyable
+{
+ public:
+ ScopedExit(std::function<void()> exit) : mExit(exit) {}
+ ~ScopedExit() { mExit(); }
+
+ private:
+ std::function<void()> mExit;
+};
+
+class CompileTask : public angle::Closure
+{
+ public:
+ CompileTask(ShHandle handle,
+ std::string &&sourcePath,
+ std::string &&source,
+ ShCompileOptions options)
+ : mHandle(handle),
+ mSourcePath(sourcePath),
+ mSource(source),
+ mOptions(options),
+ mResult(false)
+ {
+ }
+ void operator()() override
+ {
+ std::vector<const char *> srcStrings;
+ if (!mSourcePath.empty())
+ {
+ srcStrings.push_back(mSourcePath.c_str());
+ }
+ srcStrings.push_back(mSource.c_str());
+ mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions);
+ }
+ bool getResult() { return mResult; }
+
+ private:
+ ShHandle mHandle;
+ std::string mSourcePath;
+ std::string mSource;
+ ShCompileOptions mOptions;
+ bool mResult;
+};
+
ShaderState::ShaderState(ShaderType shaderType)
: mLabel(),
mShaderType(shaderType),
@@ -131,6 +177,7 @@
void Shader::onDestroy(const gl::Context *context)
{
+ resolveCompile();
mImplementation->destroy();
mBoundCompiler.set(context, nullptr);
mImplementation.reset(nullptr);
@@ -284,6 +331,8 @@
void Shader::compile(const Context *context)
{
+ resolveCompile();
+
mState.mTranslatedSource.clear();
mInfoLog.clear();
mState.mShaderVersion = 100;
@@ -307,19 +356,19 @@
// can change before the link call or another call that resolves the compile.
std::stringstream sourceStream;
-
- mLastCompileOptions = mImplementation->prepareSourceAndReturnOptions(context, &sourceStream,
- &mLastCompiledSourcePath);
- mLastCompileOptions |= (SH_OBJECT_CODE | SH_VARIABLES);
- mLastCompiledSource = sourceStream.str();
+ std::string sourcePath;
+ ShCompileOptions options =
+ mImplementation->prepareSourceAndReturnOptions(context, &sourceStream, &sourcePath);
+ options |= (SH_OBJECT_CODE | SH_VARIABLES);
+ auto source = sourceStream.str();
// Add default options to WebGL shaders to prevent unexpected behavior during compilation.
if (context->getExtensions().webglCompatibility)
{
- mLastCompileOptions |= SH_INIT_GL_POSITION;
- mLastCompileOptions |= SH_LIMIT_CALL_STACK_DEPTH;
- mLastCompileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
- mLastCompileOptions |= SH_ENFORCE_PACKING_RESTRICTIONS;
+ options |= SH_INIT_GL_POSITION;
+ options |= SH_LIMIT_CALL_STACK_DEPTH;
+ options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
+ options |= SH_ENFORCE_PACKING_RESTRICTIONS;
}
// Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
@@ -327,10 +376,21 @@
// instruct the compiler to pre-validate.
if (mRendererLimitations.shadersRequireIndexedLoopValidation)
{
- mLastCompileOptions |= SH_VALIDATE_LOOP_INDEXING;
+ options |= SH_VALIDATE_LOOP_INDEXING;
}
mCurrentMaxComputeWorkGroupInvocations = context->getCaps().maxComputeWorkGroupInvocations;
+
+ ASSERT(mBoundCompiler.get());
+ mShCompilerInstance = mBoundCompiler->getInstance(mState.mShaderType);
+ ShHandle compilerHandle = mShCompilerInstance.getHandle();
+ ASSERT(compilerHandle);
+ mCompilerResourcesString = mShCompilerInstance.getBuiltinResourcesString();
+
+ mCompileTask = std::make_shared<CompileTask>(compilerHandle, std::move(sourcePath),
+ std::move(source), options);
+ mWorkerPool = context->getWorkerThreadPool();
+ mCompileEvent = mWorkerPool->postWorkerTask(mCompileTask);
}
void Shader::resolveCompile()
@@ -340,19 +400,21 @@
return;
}
- ASSERT(mBoundCompiler.get());
- ShHandle compilerHandle = mBoundCompiler->getCompilerHandle(mState.mShaderType);
+ ASSERT(mCompileEvent.get());
+ ASSERT(mCompileTask.get());
- std::vector<const char *> srcStrings;
+ mCompileEvent->wait();
- if (!mLastCompiledSourcePath.empty())
- {
- srcStrings.push_back(mLastCompiledSourcePath.c_str());
- }
+ mCompileEvent.reset();
+ mWorkerPool.reset();
- srcStrings.push_back(mLastCompiledSource.c_str());
+ bool compiled = mCompileTask->getResult();
+ mCompileTask.reset();
- if (!sh::Compile(compilerHandle, &srcStrings[0], srcStrings.size(), mLastCompileOptions))
+ ScopedExit exit([this]() { mBoundCompiler->putInstance(std::move(mShCompilerInstance)); });
+
+ ShHandle compilerHandle = mShCompilerInstance.getHandle();
+ if (!compiled)
{
mInfoLog = sh::GetInfoLog(compilerHandle);
WARN() << std::endl << mInfoLog;
@@ -469,7 +531,7 @@
ASSERT(!mState.mTranslatedSource.empty());
- bool success = mImplementation->postTranslateCompile(mBoundCompiler.get(), &mInfoLog);
+ bool success = mImplementation->postTranslateCompile(&mShCompilerInstance, &mInfoLog);
mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
}
@@ -509,6 +571,11 @@
return mState.mCompileStatus == CompileStatus::COMPILED;
}
+bool Shader::isCompleted()
+{
+ return (!mState.compilePending() || mCompileEvent->isReady());
+}
+
int Shader::getShaderVersion()
{
resolveCompile();
@@ -640,8 +707,7 @@
const std::string &Shader::getCompilerResourcesString() const
{
- ASSERT(mBoundCompiler.get());
- return mBoundCompiler->getBuiltinResourcesString(mState.mShaderType);
+ return mCompilerResourcesString;
}
} // namespace gl
diff --git a/src/libANGLE/Shader.h b/src/libANGLE/Shader.h
index ec46d66..27be6ef 100644
--- a/src/libANGLE/Shader.h
+++ b/src/libANGLE/Shader.h
@@ -22,6 +22,7 @@
#include "common/Optional.h"
#include "common/angleutils.h"
+#include "libANGLE/Compiler.h"
#include "libANGLE/Debug.h"
#include "libANGLE/angletypes.h"
@@ -32,13 +33,19 @@
class ShaderSh;
}
+namespace angle
+{
+class WaitableEvent;
+class WorkerThreadPool;
+} // namespace angle
+
namespace gl
{
-class Compiler;
class ContextState;
struct Limitations;
class ShaderProgramManager;
class Context;
+class CompileTask;
// We defer the compile until link time, or until properties are queried.
enum class CompileStatus
@@ -146,6 +153,7 @@
void compile(const Context *context);
bool isCompiled();
+ bool isCompleted();
void addRef();
void release(const Context *context);
@@ -190,9 +198,6 @@
void resolveCompile();
ShaderState mState;
- std::string mLastCompiledSource;
- std::string mLastCompiledSourcePath;
- ShCompileOptions mLastCompileOptions;
std::unique_ptr<rx::ShaderImpl> mImplementation;
const gl::Limitations &mRendererLimitations;
const GLuint mHandle;
@@ -203,6 +208,11 @@
// We keep a reference to the translator in order to defer compiles while preserving settings.
BindingPointer<Compiler> mBoundCompiler;
+ ShCompilerInstance mShCompilerInstance;
+ std::shared_ptr<CompileTask> mCompileTask;
+ std::shared_ptr<angle::WorkerThreadPool> mWorkerPool;
+ std::shared_ptr<angle::WaitableEvent> mCompileEvent;
+ std::string mCompilerResourcesString;
ShaderProgramManager *mResourceManager;
diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp
index 12a51a3..66d2d48 100644
--- a/src/libANGLE/queryutils.cpp
+++ b/src/libANGLE/queryutils.cpp
@@ -1167,9 +1167,7 @@
*params = shader->isCompiled() ? GL_TRUE : GL_FALSE;
return;
case GL_COMPLETION_STATUS_KHR:
- // TODO(jie.a.chen@intel.com): Parallelize shader compilation.
- // http://crbug.com/849576
- *params = shader->isCompiled() ? GL_TRUE : GL_FALSE;
+ *params = shader->isCompleted() ? GL_TRUE : GL_FALSE;
return;
case GL_INFO_LOG_LENGTH:
*params = shader->getInfoLogLength();
diff --git a/src/libANGLE/renderer/ShaderImpl.h b/src/libANGLE/renderer/ShaderImpl.h
index 2b5c404..2f9d57f 100644
--- a/src/libANGLE/renderer/ShaderImpl.h
+++ b/src/libANGLE/renderer/ShaderImpl.h
@@ -28,7 +28,7 @@
std::stringstream *sourceStream,
std::string *sourcePath) = 0;
// Returns success for compiling on the driver. Returns success.
- virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;
+ virtual bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) = 0;
virtual std::string getDebugInfo() const = 0;
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
index 0d27f78..ff50019 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
@@ -174,7 +174,7 @@
return *uniformRegisterMap;
}
-bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
+bool ShaderD3D::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
{
// TODO(jmadill): We shouldn't need to cache this.
mCompilerOutputType = compiler->getShaderOutputType();
@@ -199,7 +199,7 @@
mRequiresIEEEStrictCompiling =
translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
- ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
+ ShHandle compilerHandle = compiler->getHandle();
mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle));
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/libANGLE/renderer/d3d/ShaderD3D.h
index 9239df7..2e357e3 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.h
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.h
@@ -42,7 +42,7 @@
ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream,
std::string *sourcePath) override;
- bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override;
+ bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override;
// D3D-specific methods
diff --git a/src/libANGLE/renderer/gl/ShaderGL.cpp b/src/libANGLE/renderer/gl/ShaderGL.cpp
index 6891219..898a06d 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.cpp
+++ b/src/libANGLE/renderer/gl/ShaderGL.cpp
@@ -142,7 +142,7 @@
return options;
}
-bool ShaderGL::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
+bool ShaderGL::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
{
// Translate the ESSL into GLSL
const char *translatedSourceCString = mData.getTranslatedSource().c_str();
diff --git a/src/libANGLE/renderer/gl/ShaderGL.h b/src/libANGLE/renderer/gl/ShaderGL.h
index 0ba8843..7181d24 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.h
+++ b/src/libANGLE/renderer/gl/ShaderGL.h
@@ -32,7 +32,7 @@
ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream,
std::string *sourcePath) override;
- bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override;
+ bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override;
GLuint getShaderID() const;
diff --git a/src/libANGLE/renderer/null/ShaderNULL.cpp b/src/libANGLE/renderer/null/ShaderNULL.cpp
index 4e3b9e7..f6edc87 100644
--- a/src/libANGLE/renderer/null/ShaderNULL.cpp
+++ b/src/libANGLE/renderer/null/ShaderNULL.cpp
@@ -30,7 +30,7 @@
return 0;
}
-bool ShaderNULL::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
+bool ShaderNULL::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
{
return true;
}
diff --git a/src/libANGLE/renderer/null/ShaderNULL.h b/src/libANGLE/renderer/null/ShaderNULL.h
index 04a58c0..0892fa1 100644
--- a/src/libANGLE/renderer/null/ShaderNULL.h
+++ b/src/libANGLE/renderer/null/ShaderNULL.h
@@ -26,7 +26,7 @@
std::stringstream *sourceStream,
std::string *sourcePath) override;
// Returns success for compiling on the driver. Returns success.
- bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override;
+ bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override;
};
diff --git a/src/libANGLE/renderer/vulkan/ShaderVk.cpp b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
index c1e21b6..7e2fad7 100644
--- a/src/libANGLE/renderer/vulkan/ShaderVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ShaderVk.cpp
@@ -30,7 +30,7 @@
return SH_INITIALIZE_UNINITIALIZED_LOCALS;
}
-bool ShaderVk::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
+bool ShaderVk::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
{
// No work to do here.
return true;
diff --git a/src/libANGLE/renderer/vulkan/ShaderVk.h b/src/libANGLE/renderer/vulkan/ShaderVk.h
index 5e42907..5990177 100644
--- a/src/libANGLE/renderer/vulkan/ShaderVk.h
+++ b/src/libANGLE/renderer/vulkan/ShaderVk.h
@@ -26,7 +26,7 @@
std::stringstream *sourceStream,
std::string *sourcePath) override;
// Returns success for compiling on the driver. Returns success.
- bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override;
+ bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override;
};
diff --git a/src/tests/gl_tests/ParallelShaderCompileTest.cpp b/src/tests/gl_tests/ParallelShaderCompileTest.cpp
index 21788d2..fd3277e 100644
--- a/src/tests/gl_tests/ParallelShaderCompileTest.cpp
+++ b/src/tests/gl_tests/ParallelShaderCompileTest.cpp
@@ -51,11 +51,39 @@
public:
ClearColorWithDraw(GLubyte color) : mColor(color, color, color, 255) {}
- bool compileAndLink()
+ bool compile()
{
- mProgram =
- CompileProgramParallel(insertRandomString(essl1_shaders::vs::Simple()),
- insertRandomString(essl1_shaders::fs::UniformColor()));
+ mVertexShader =
+ compileShader(GL_VERTEX_SHADER, insertRandomString(essl1_shaders::vs::Simple()));
+ mFragmentShader = compileShader(GL_FRAGMENT_SHADER,
+ insertRandomString(essl1_shaders::fs::UniformColor()));
+ return (mVertexShader != 0 && mFragmentShader != 0);
+ }
+
+ bool isCompileCompleted()
+ {
+ GLint status;
+ glGetShaderiv(mVertexShader, GL_COMPLETION_STATUS_KHR, &status);
+ if (status == GL_TRUE)
+ {
+ glGetShaderiv(mFragmentShader, GL_COMPLETION_STATUS_KHR, &status);
+ return (status == GL_TRUE);
+ }
+ return false;
+ }
+
+ bool link()
+ {
+ mProgram = 0;
+ if (checkShader(mVertexShader) && checkShader(mFragmentShader))
+ {
+ mProgram = glCreateProgram();
+ glAttachShader(mProgram, mVertexShader);
+ glAttachShader(mProgram, mFragmentShader);
+ glLinkProgram(mProgram);
+ }
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
return (mProgram != 0);
}
@@ -95,7 +123,47 @@
return ostream.str();
}
+ GLuint compileShader(GLenum type, const std::string &source)
+ {
+ GLuint shader = glCreateShader(type);
+
+ const char *sourceArray[1] = {source.c_str()};
+ glShaderSource(shader, 1, sourceArray, nullptr);
+ glCompileShader(shader);
+ return shader;
+ }
+
+ bool checkShader(GLuint shader)
+ {
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+
+ if (compileResult == 0)
+ {
+ GLint infoLogLength;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+ // Info log length includes the null terminator, so 1 means that the info log is an
+ // empty string.
+ if (infoLogLength > 1)
+ {
+ std::vector<GLchar> infoLog(infoLogLength);
+ glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr,
+ &infoLog[0]);
+ std::cerr << "shader compilation failed: " << &infoLog[0];
+ }
+ else
+ {
+ std::cerr << "shader compilation failed. <Empty log message>";
+ }
+ std::cerr << std::endl;
+ }
+ return (compileResult == GL_TRUE);
+ }
+
GLColor mColor;
+ GLuint mVertexShader;
+ GLuint mFragmentShader;
GLuint mProgram;
};
};
@@ -118,25 +186,48 @@
{
ANGLE_SKIP_TEST_IF(!ensureParallelShaderCompileExtensionAvailable());
- std::vector<std::unique_ptr<ClearColorWithDraw>> tasks;
+ std::vector<std::unique_ptr<ClearColorWithDraw>> compileTasks;
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));
+ bool isCompiling = task->compile();
+ ASSERT_TRUE(isCompiling);
+ compileTasks.push_back(std::move(task));
}
+
constexpr unsigned int kPollInterval = 100;
- while (!tasks.empty())
+
+ std::vector<std::unique_ptr<ClearColorWithDraw>> linkTasks;
+ while (!compileTasks.empty())
{
- for (unsigned int i = 0; i < tasks.size();)
+ for (unsigned int i = 0; i < compileTasks.size();)
{
- auto &task = tasks[i];
+ auto &task = compileTasks[i];
+
+ if (task->isCompileCompleted())
+ {
+ bool isLinking = task->link();
+ ASSERT_TRUE(isLinking);
+ linkTasks.push_back(std::move(task));
+ compileTasks.erase(compileTasks.begin() + i);
+ continue;
+ }
+ ++i;
+ }
+ Sleep(kPollInterval);
+ }
+
+ while (!linkTasks.empty())
+ {
+ for (unsigned int i = 0; i < linkTasks.size();)
+ {
+ auto &task = linkTasks[i];
+
if (task->isLinkCompleted())
{
task->drawAndVerify(this);
- tasks.erase(tasks.begin() + i);
+ linkTasks.erase(linkTasks.begin() + i);
continue;
}
++i;