ParallelCompile: add GL backend support
For GL backend, at first each worker thread must have a naitve context
for its own to work in. These worker contexts have to be shared from
the main context, so that all shader and program objects are seen in
any context. This extends backend displays to create and destroy the
worker contexts. RendererGL manages and allocates them to the worker
threads. ShaderImpl has a new compile method added to do the actual
glCompile work in worker thread. The ProgramGL's link method is broken
down by introducing the LinkEventGL class.
Bug: chromium:849576
Change-Id: Idc2c51b4b6c978781ae77810e62c480acc67ebb5
Reviewed-on: https://chromium-review.googlesource.com/c/1373015
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 1bda45c..0cfac31 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -1098,6 +1098,7 @@
// The code gets compiled into binaries.
angle::Result Program::link(const Context *context)
{
+ ASSERT(mLinkResolved);
const auto &data = context->getState();
auto *platform = ANGLEPlatformCurrent();
diff --git a/src/libANGLE/Shader.cpp b/src/libANGLE/Shader.cpp
index 4d963f8..b1831d8 100644
--- a/src/libANGLE/Shader.cpp
+++ b/src/libANGLE/Shader.cpp
@@ -108,17 +108,20 @@
std::function<void()> mExit;
};
+using CompileImplFunctor = std::function<void(const std::string &)>;
class CompileTask : public angle::Closure
{
public:
CompileTask(ShHandle handle,
std::string &&sourcePath,
std::string &&source,
- ShCompileOptions options)
+ ShCompileOptions options,
+ CompileImplFunctor &&functor)
: mHandle(handle),
mSourcePath(sourcePath),
mSource(source),
mOptions(options),
+ mCompileImplFunctor(functor),
mResult(false)
{}
void operator()() override
@@ -130,6 +133,10 @@
}
srcStrings.push_back(mSource.c_str());
mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions);
+ if (mResult)
+ {
+ mCompileImplFunctor(sh::GetObjectCode(mHandle));
+ }
}
bool getResult() { return mResult; }
@@ -138,6 +145,7 @@
std::string mSourcePath;
std::string mSource;
ShCompileOptions mOptions;
+ CompileImplFunctor mCompileImplFunctor;
bool mResult;
};
@@ -385,9 +393,21 @@
ASSERT(compilerHandle);
mCompilerResourcesString = mShCompilerInstance.getBuiltinResourcesString();
- mCompileTask = std::make_shared<CompileTask>(compilerHandle, std::move(sourcePath),
- std::move(source), options);
mWorkerPool = context->getWorkerThreadPool();
+ std::function<void(const std::string &)> compileImplFunctor;
+ if (mWorkerPool->isAsync())
+ {
+ compileImplFunctor = [this](const std::string &source) {
+ mImplementation->compileAsync(source);
+ };
+ }
+ else
+ {
+ compileImplFunctor = [](const std::string &source) {};
+ }
+ mCompileTask =
+ std::make_shared<CompileTask>(compilerHandle, std::move(sourcePath), std::move(source),
+ options, std::move(compileImplFunctor));
mCompileEvent = mWorkerPool->postWorkerTask(mCompileTask);
}
diff --git a/src/libANGLE/WorkerThread.cpp b/src/libANGLE/WorkerThread.cpp
index d9baac1..565e959 100644
--- a/src/libANGLE/WorkerThread.cpp
+++ b/src/libANGLE/WorkerThread.cpp
@@ -49,6 +49,7 @@
public:
std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
void setMaxThreads(size_t maxThreads) override;
+ bool isAsync() override;
};
// SingleThreadedWorkerPool implementation.
@@ -61,6 +62,11 @@
void SingleThreadedWorkerPool::setMaxThreads(size_t maxThreads) {}
+bool SingleThreadedWorkerPool::isAsync()
+{
+ return false;
+}
+
#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
class AsyncWaitableEvent final : public WaitableEvent
{
@@ -120,6 +126,7 @@
std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
void setMaxThreads(size_t maxThreads) override;
+ bool isAsync() override;
private:
void checkToRunPendingTasks();
@@ -156,6 +163,11 @@
checkToRunPendingTasks();
}
+bool AsyncWorkerPool::isAsync()
+{
+ return true;
+}
+
void AsyncWorkerPool::checkToRunPendingTasks()
{
std::lock_guard<std::mutex> lock(mMutex);
diff --git a/src/libANGLE/WorkerThread.h b/src/libANGLE/WorkerThread.h
index c6f8018..8693ab2 100644
--- a/src/libANGLE/WorkerThread.h
+++ b/src/libANGLE/WorkerThread.h
@@ -68,6 +68,8 @@
virtual std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) = 0;
virtual void setMaxThreads(size_t maxThreads) = 0;
+
+ virtual bool isAsync() = 0;
};
} // namespace angle
diff --git a/src/libANGLE/features.h b/src/libANGLE/features.h
index f2bb0d1..9ff7dfa 100644
--- a/src/libANGLE/features.h
+++ b/src/libANGLE/features.h
@@ -53,13 +53,8 @@
#endif
// Controls if our threading code uses std::async or falls back to single-threaded operations.
-// TODO(jmadill): Enable on Linux once STL chrono headers are updated.
#if !defined(ANGLE_STD_ASYNC_WORKERS)
-# if defined(ANGLE_PLATFORM_WINDOWS)
-# define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED
-# else
-# define ANGLE_STD_ASYNC_WORKERS ANGLE_DISABLED
-# endif // defined(ANGLE_PLATFORM_WINDOWS)
+# define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED
#endif // !defined(ANGLE_STD_ASYNC_WORKERS)
// Force thread safety in all of ANGLE by locking a global mutex in every ANGLE entry point.
diff --git a/src/libANGLE/renderer/ShaderImpl.h b/src/libANGLE/renderer/ShaderImpl.h
index be298e4..273c16d 100644
--- a/src/libANGLE/renderer/ShaderImpl.h
+++ b/src/libANGLE/renderer/ShaderImpl.h
@@ -27,6 +27,10 @@
virtual ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream,
std::string *sourcePath) = 0;
+
+ // Uses the GL driver to compile the shader source in a worker thread.
+ virtual void compileAsync(const std::string &source) {}
+
// Returns success for compiling on the driver. Returns success.
virtual bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) = 0;
diff --git a/src/libANGLE/renderer/gl/ContextGL.cpp b/src/libANGLE/renderer/gl/ContextGL.cpp
index 69566c9..2cb10e2 100644
--- a/src/libANGLE/renderer/gl/ContextGL.cpp
+++ b/src/libANGLE/renderer/gl/ContextGL.cpp
@@ -55,13 +55,13 @@
const FunctionsGL *functions = getFunctions();
GLuint shader = functions->createShader(ToGLenum(data.getShaderType()));
- return new ShaderGL(data, shader, mRenderer->getMultiviewImplementationType(), functions);
+ return new ShaderGL(data, shader, mRenderer->getMultiviewImplementationType(), mRenderer);
}
ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
{
return new ProgramGL(data, getFunctions(), getWorkaroundsGL(), getStateManager(),
- getExtensions().pathRendering);
+ getExtensions().pathRendering, mRenderer);
}
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
diff --git a/src/libANGLE/renderer/gl/ContextGL.h b/src/libANGLE/renderer/gl/ContextGL.h
index 49407fe..9e513cf 100644
--- a/src/libANGLE/renderer/gl/ContextGL.h
+++ b/src/libANGLE/renderer/gl/ContextGL.h
@@ -228,6 +228,7 @@
angle::Result setDrawIndirectState(const gl::Context *context);
+ protected:
std::shared_ptr<RendererGL> mRenderer;
};
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index 02b6b5f..b5422e1 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -16,9 +16,11 @@
#include "libANGLE/Context.h"
#include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/Uniform.h"
+#include "libANGLE/WorkerThread.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/ShaderGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h"
@@ -31,14 +33,17 @@
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
StateManagerGL *stateManager,
- bool enablePathRendering)
+ bool enablePathRendering,
+ const std::shared_ptr<RendererGL> &renderer)
: ProgramImpl(data),
mFunctions(functions),
mWorkarounds(workarounds),
mStateManager(stateManager),
mEnablePathRendering(enablePathRendering),
mMultiviewBaseViewLayerIndexUniformLocation(-1),
- mProgramID(0)
+ mProgramID(0),
+ mRenderer(renderer),
+ mLinkedInParallel(false)
{
ASSERT(mFunctions);
ASSERT(mStateManager);
@@ -125,18 +130,54 @@
mFunctions->programParameteri(mProgramID, GL_PROGRAM_SEPARABLE, separable ? GL_TRUE : GL_FALSE);
}
+using LinkImplFunctor = std::function<bool()>;
+class ProgramGL::LinkTask final : public angle::Closure
+{
+ public:
+ LinkTask(LinkImplFunctor &&functor) : mLinkImplFunctor(functor), mFallbackToMainContext(false)
+ {}
+
+ void operator()() override { mFallbackToMainContext = mLinkImplFunctor(); }
+ bool fallbackToMainContext() { return mFallbackToMainContext; }
+
+ private:
+ LinkImplFunctor mLinkImplFunctor;
+ bool mFallbackToMainContext;
+};
+
+using PostLinkImplFunctor = std::function<angle::Result(bool)>;
+class ProgramGL::LinkEventGL final : public LinkEvent
+{
+ public:
+ LinkEventGL(std::shared_ptr<angle::WorkerThreadPool> workerPool,
+ std::shared_ptr<ProgramGL::LinkTask> linkTask,
+ PostLinkImplFunctor &&functor)
+ : mWorkerPool(workerPool),
+ mLinkTask(linkTask),
+ mWaitableEvent(
+ std::shared_ptr<angle::WaitableEvent>(workerPool->postWorkerTask(mLinkTask))),
+ mPostLinkImplFunctor(functor)
+ {}
+
+ angle::Result wait(const gl::Context *context) override
+ {
+ mWaitableEvent->wait();
+ return mPostLinkImplFunctor(mLinkTask->fallbackToMainContext());
+ }
+
+ bool isLinking() override { return !mWaitableEvent->isReady(); }
+
+ private:
+ std::shared_ptr<angle::WorkerThreadPool> mWorkerPool;
+ std::shared_ptr<ProgramGL::LinkTask> mLinkTask;
+ std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
+ PostLinkImplFunctor mPostLinkImplFunctor;
+};
+
std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
{
- // TODO(jie.a.chen@intel.com): Parallelize linking.
- return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
-}
-
-angle::Result ProgramGL::linkImpl(const gl::Context *context,
- const gl::ProgramLinkedResources &resources,
- gl::InfoLog &infoLog)
-{
preLink();
if (mState.getAttachedShader(gl::ShaderType::Compute))
@@ -145,12 +186,6 @@
GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute));
mFunctions->attachShader(mProgramID, computeShaderGL->getShaderID());
-
- // Link and verify
- mFunctions->linkProgram(mProgramID);
-
- // Detach the shaders
- mFunctions->detachShader(mProgramID, computeShaderGL->getShaderID());
}
else
{
@@ -321,34 +356,85 @@
}
}
}
+ }
+ auto workerPool = context->getWorkerThreadPool();
+ auto linkTask = std::make_shared<LinkTask>([this]() {
+ std::string infoLog;
+ ScopedWorkerContextGL worker(mRenderer.get(), &infoLog);
+ if (!worker())
+ {
+#if !defined(NDEBUG)
+ WARN() << "bindWorkerContext failed." << std::endl << infoLog;
+#endif
+ // Fallback to the main context.
+ return true;
+ }
- // Link and verify
mFunctions->linkProgram(mProgramID);
- // Detach the shaders
- mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID());
- mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID());
- if (geometryShaderGL)
+ // Make sure the driver actually does the link job.
+ GLint linkStatus = GL_FALSE;
+ mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
+
+ return false;
+ });
+
+ auto postLinkImplTask = [this, &infoLog, &resources](bool fallbackToMainContext) {
+ if (fallbackToMainContext)
{
- mFunctions->detachShader(mProgramID, geometryShaderGL->getShaderID());
+ mFunctions->linkProgram(mProgramID);
}
- }
- // Verify the link
- if (!checkLinkStatus(infoLog))
+ if (mState.getAttachedShader(gl::ShaderType::Compute))
+ {
+ const ShaderGL *computeShaderGL =
+ GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute));
+
+ mFunctions->detachShader(mProgramID, computeShaderGL->getShaderID());
+ }
+ else
+ {
+ const ShaderGL *vertexShaderGL =
+ GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Vertex));
+ const ShaderGL *fragmentShaderGL =
+ GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Fragment));
+ const ShaderGL *geometryShaderGL = rx::SafeGetImplAs<ShaderGL, gl::Shader>(
+ mState.getAttachedShader(gl::ShaderType::Geometry));
+
+ // Detach the shaders
+ mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID());
+ mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID());
+ if (geometryShaderGL)
+ {
+ mFunctions->detachShader(mProgramID, geometryShaderGL->getShaderID());
+ }
+ }
+ // Verify the link
+ if (!checkLinkStatus(infoLog))
+ {
+ return angle::Result::Incomplete;
+ }
+
+ if (mWorkarounds.alwaysCallUseProgramAfterLink)
+ {
+ mStateManager->forceUseProgram(mProgramID);
+ }
+
+ linkResources(resources);
+ postLink();
+
+ return angle::Result::Continue;
+ };
+
+ if (workerPool->isAsync() && (!mWorkarounds.dontRelinkProgramsInParallel || !mLinkedInParallel))
{
- return angle::Result::Incomplete;
+ mLinkedInParallel = true;
+ return std::make_unique<LinkEventGL>(workerPool, linkTask, postLinkImplTask);
}
-
- if (mWorkarounds.alwaysCallUseProgramAfterLink)
+ else
{
- mStateManager->forceUseProgram(mProgramID);
+ return std::make_unique<LinkEventDone>(postLinkImplTask(true));
}
-
- linkResources(resources);
- postLink();
-
- return angle::Result::Continue;
}
GLboolean ProgramGL::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/)
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index ad043a6..73f5afe 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -19,6 +19,7 @@
{
class FunctionsGL;
+class RendererGL;
class StateManagerGL;
class ProgramGL : public ProgramImpl
@@ -28,7 +29,8 @@
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
StateManagerGL *stateManager,
- bool enablePathRendering);
+ bool enablePathRendering,
+ const std::shared_ptr<RendererGL> &renderer);
~ProgramGL() override;
angle::Result load(const gl::Context *context,
@@ -114,12 +116,12 @@
const gl::Program::DirtyBits &dirtyBits) override;
private:
+ class LinkTask;
+ class LinkEventGL;
+
void preLink();
bool checkLinkStatus(gl::InfoLog &infoLog);
void postLink();
- angle::Result linkImpl(const gl::Context *contextImpl,
- const gl::ProgramLinkedResources &resources,
- gl::InfoLog &infoLog);
void reapplyUBOBindingsIfNeeded(const gl::Context *context);
@@ -161,6 +163,10 @@
GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID;
+
+ std::shared_ptr<RendererGL> mRenderer;
+
+ bool mLinkedInParallel;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index 9622e19..5294846 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -222,6 +222,11 @@
SafeDelete(mBlitter);
SafeDelete(mMultiviewClearer);
SafeDelete(mStateManager);
+
+ std::lock_guard<std::mutex> lock(mWorkerMutex);
+
+ ASSERT(mCurrentWorkerContexts.empty());
+ mWorkerContextPool.clear();
}
angle::Result RendererGL::flush()
@@ -559,4 +564,71 @@
return angle::Result::Continue;
}
+bool RendererGL::bindWorkerContext(std::string *infoLog)
+{
+ std::thread::id threadID = std::this_thread::get_id();
+ std::lock_guard<std::mutex> lock(mWorkerMutex);
+ std::unique_ptr<WorkerContext> workerContext;
+ if (!mWorkerContextPool.empty())
+ {
+ auto it = mWorkerContextPool.begin();
+ workerContext = std::move(*it);
+ mWorkerContextPool.erase(it);
+ }
+ else
+ {
+ WorkerContext *newContext = createWorkerContext(infoLog);
+ if (newContext == nullptr)
+ {
+ return false;
+ }
+ workerContext.reset(newContext);
+ }
+
+ if (!workerContext->makeCurrent())
+ {
+ mWorkerContextPool.push_back(std::move(workerContext));
+ return false;
+ }
+ mCurrentWorkerContexts[threadID] = std::move(workerContext);
+ return true;
+}
+
+void RendererGL::unbindWorkerContext()
+{
+ std::thread::id threadID = std::this_thread::get_id();
+ std::lock_guard<std::mutex> lock(mWorkerMutex);
+
+ auto it = mCurrentWorkerContexts.find(threadID);
+ ASSERT(it != mCurrentWorkerContexts.end());
+ (*it).second->unmakeCurrent();
+ mWorkerContextPool.push_back(std::move((*it).second));
+ mCurrentWorkerContexts.erase(it);
+}
+
+unsigned int RendererGL::getMaxWorkerContexts()
+{
+ // No more than 16 worker contexts.
+ return std::min(16u, std::thread::hardware_concurrency());
+}
+
+ScopedWorkerContextGL::ScopedWorkerContextGL(RendererGL *renderer, std::string *infoLog)
+ : mRenderer(renderer)
+{
+ mValid = mRenderer->bindWorkerContext(infoLog);
+}
+
+ScopedWorkerContextGL::~ScopedWorkerContextGL()
+{
+ if (mValid)
+ {
+ mRenderer->unbindWorkerContext();
+ }
+}
+
+bool ScopedWorkerContextGL::operator()() const
+{
+ return mValid;
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/RendererGL.h b/src/libANGLE/renderer/gl/RendererGL.h
index 9ce3d3c..f1eb396 100644
--- a/src/libANGLE/renderer/gl/RendererGL.h
+++ b/src/libANGLE/renderer/gl/RendererGL.h
@@ -9,6 +9,10 @@
#ifndef LIBANGLE_RENDERER_GL_RENDERERGL_H_
#define LIBANGLE_RENDERER_GL_RENDERERGL_H_
+#include <list>
+#include <mutex>
+#include <thread>
+
#include "libANGLE/Caps.h"
#include "libANGLE/Error.h"
#include "libANGLE/Version.h"
@@ -39,8 +43,33 @@
class ClearMultiviewGL;
class ContextImpl;
class FunctionsGL;
+class RendererGL;
class StateManagerGL;
+// WorkerContext wraps a native GL context shared from the main context. It is used by the workers
+// for khr_parallel_shader_compile.
+class WorkerContext : angle::NonCopyable
+{
+ public:
+ virtual ~WorkerContext(){};
+
+ virtual bool makeCurrent() = 0;
+ virtual void unmakeCurrent() = 0;
+};
+
+class ScopedWorkerContextGL
+{
+ public:
+ ScopedWorkerContextGL(RendererGL *renderer, std::string *infoLog);
+ ~ScopedWorkerContextGL();
+
+ bool operator()() const;
+
+ private:
+ RendererGL *mRenderer = nullptr;
+ bool mValid = false;
+};
+
class RendererGL : angle::NonCopyable
{
public:
@@ -149,6 +178,14 @@
angle::Result memoryBarrier(GLbitfield barriers);
angle::Result memoryBarrierByRegion(GLbitfield barriers);
+ bool bindWorkerContext(std::string *infoLog);
+ void unbindWorkerContext();
+
+ static unsigned int getMaxWorkerContexts();
+
+ protected:
+ virtual WorkerContext *createWorkerContext(std::string *infoLog) = 0;
+
private:
void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps,
@@ -174,6 +211,13 @@
mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations;
mutable MultiviewImplementationTypeGL mMultiviewImplementationType;
+
+ // The thread-to-context mapping for the currently active worker threads.
+ std::unordered_map<std::thread::id, std::unique_ptr<WorkerContext>> mCurrentWorkerContexts;
+ // The worker contexts available to use.
+ std::list<std::unique_ptr<WorkerContext>> mWorkerContextPool;
+ // Protect the concurrent accesses to worker contexts.
+ std::mutex mWorkerMutex;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/ShaderGL.cpp b/src/libANGLE/renderer/gl/ShaderGL.cpp
index ed4bc17..e4c6c2e 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.cpp
+++ b/src/libANGLE/renderer/gl/ShaderGL.cpp
@@ -23,11 +23,13 @@
ShaderGL::ShaderGL(const gl::ShaderState &data,
GLuint shaderID,
MultiviewImplementationTypeGL multiviewImplementationType,
- const FunctionsGL *functions)
+ const std::shared_ptr<RendererGL> &renderer)
: ShaderImpl(data),
mShaderID(shaderID),
mMultiviewImplementationType(multiviewImplementationType),
- mFunctions(functions)
+ mRenderer(renderer),
+ mFallbackToMainThread(true),
+ mCompileStatus(GL_FALSE)
{}
ShaderGL::~ShaderGL()
@@ -37,7 +39,7 @@
void ShaderGL::destroy()
{
- mFunctions->deleteShader(mShaderID);
+ mRenderer->getFunctions()->deleteShader(mShaderID);
mShaderID = 0;
}
@@ -138,41 +140,70 @@
options |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
}
+ mFallbackToMainThread = true;
+
return options;
}
-bool ShaderGL::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
+void ShaderGL::compileAndCheckShader(const char *source)
{
- // Translate the ESSL into GLSL
- const char *translatedSourceCString = mData.getTranslatedSource().c_str();
-
- // Set the source
- mFunctions->shaderSource(mShaderID, 1, &translatedSourceCString, nullptr);
- mFunctions->compileShader(mShaderID);
+ const FunctionsGL *functions = mRenderer->getFunctions();
+ functions->shaderSource(mShaderID, 1, &source, nullptr);
+ functions->compileShader(mShaderID);
// Check for compile errors from the native driver
- GLint compileStatus = GL_FALSE;
- mFunctions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &compileStatus);
- if (compileStatus == GL_FALSE)
+ mCompileStatus = GL_FALSE;
+ functions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &mCompileStatus);
+ if (mCompileStatus == GL_FALSE)
{
// Compilation failed, put the error into the info log
GLint infoLogLength = 0;
- mFunctions->getShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
+ functions->getShaderiv(mShaderID, 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<char> buf(infoLogLength);
- mFunctions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]);
+ functions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]);
- *infoLog = &buf[0];
- WARN() << std::endl << *infoLog;
+ mInfoLog = &buf[0];
+ WARN() << std::endl << mInfoLog;
}
else
{
WARN() << std::endl << "Shader compilation failed with no info log.";
}
+ }
+}
+
+void ShaderGL::compileAsync(const std::string &source)
+{
+ std::string infoLog;
+ ScopedWorkerContextGL worker(mRenderer.get(), &infoLog);
+ if (worker())
+ {
+ compileAndCheckShader(source.c_str());
+ mFallbackToMainThread = false;
+ }
+ else
+ {
+#if !defined(NDEBUG)
+ WARN() << "bindWorkerContext failed." << std::endl << infoLog;
+#endif
+ }
+}
+
+bool ShaderGL::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog)
+{
+ if (mFallbackToMainThread)
+ {
+ const char *translatedSourceCString = mData.getTranslatedSource().c_str();
+ compileAndCheckShader(translatedSourceCString);
+ }
+ if (mCompileStatus == GL_FALSE)
+ {
+ *infoLog = mInfoLog;
return false;
}
diff --git a/src/libANGLE/renderer/gl/ShaderGL.h b/src/libANGLE/renderer/gl/ShaderGL.h
index 41cff4a..cb10679 100644
--- a/src/libANGLE/renderer/gl/ShaderGL.h
+++ b/src/libANGLE/renderer/gl/ShaderGL.h
@@ -13,7 +13,7 @@
namespace rx
{
-class FunctionsGL;
+class RendererGL;
struct WorkaroundsGL;
enum class MultiviewImplementationTypeGL;
@@ -23,7 +23,7 @@
ShaderGL(const gl::ShaderState &data,
GLuint shaderID,
MultiviewImplementationTypeGL multiviewImplementationType,
- const FunctionsGL *functions);
+ const std::shared_ptr<RendererGL> &renderer);
~ShaderGL() override;
void destroy() override;
@@ -32,15 +32,21 @@
ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream,
std::string *sourcePath) override;
+ void compileAsync(const std::string &source) override;
bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override;
GLuint getShaderID() const;
private:
+ void compileAndCheckShader(const char *source);
+
GLuint mShaderID;
MultiviewImplementationTypeGL mMultiviewImplementationType;
- const FunctionsGL *mFunctions;
+ std::shared_ptr<RendererGL> mRenderer;
+ bool mFallbackToMainThread;
+ GLint mCompileStatus;
+ std::string mInfoLog;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/WorkaroundsGL.h b/src/libANGLE/renderer/gl/WorkaroundsGL.h
index 3e705fa..5976fd1 100644
--- a/src/libANGLE/renderer/gl/WorkaroundsGL.h
+++ b/src/libANGLE/renderer/gl/WorkaroundsGL.h
@@ -167,6 +167,11 @@
// Older Qualcomm drivers generate errors when querying the number of bits in timer queries, ex:
// GetQueryivEXT(GL_TIME_ELAPSED, GL_QUERY_COUNTER_BITS). http://anglebug.com/3027
bool queryCounterBitsGeneratesErrors = false;
+
+ // Re-linking a program in parallel is buggy on some Intel Windows OpenGL drivers and Android
+ // platforms.
+ // http://anglebug.com/3045
+ bool dontRelinkProgramsInParallel = false;
};
inline WorkaroundsGL::WorkaroundsGL() = default;
diff --git a/src/libANGLE/renderer/gl/cgl/DisplayCGL.h b/src/libANGLE/renderer/gl/cgl/DisplayCGL.h
index 35e3ad0..1664511 100644
--- a/src/libANGLE/renderer/gl/cgl/DisplayCGL.h
+++ b/src/libANGLE/renderer/gl/cgl/DisplayCGL.h
@@ -14,9 +14,14 @@
struct _CGLContextObject;
typedef _CGLContextObject *CGLContextObj;
+struct _CGLPixelFormatObject;
+typedef _CGLPixelFormatObject *CGLPixelFormatObj;
+
namespace rx
{
+class WorkerContext;
+
class DisplayCGL : public DisplayGL
{
public:
@@ -67,6 +72,8 @@
CGLContextObj getCGLContext() const;
+ WorkerContext *createWorkerContext(std::string *infoLog);
+
private:
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
@@ -77,6 +84,7 @@
egl::Display *mEGLDisplay;
CGLContextObj mContext;
+ CGLPixelFormatObj mPixelFormat;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm b/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
index 6c24d4d..43eeeb1 100644
--- a/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
+++ b/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
@@ -15,9 +15,9 @@
#include "common/debug.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/gl/ContextGL.h"
-#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
+#include "libANGLE/renderer/gl/cgl/RendererCGL.h"
#include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
namespace
@@ -49,7 +49,7 @@
};
DisplayCGL::DisplayCGL(const egl::DisplayState &state)
- : DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr)
+ : DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr), mPixelFormat(nullptr)
{}
DisplayCGL::~DisplayCGL() {}
@@ -58,22 +58,21 @@
{
mEGLDisplay = display;
- CGLPixelFormatObj pixelFormat;
{
// TODO(cwallez) investigate which pixel format we want
CGLPixelFormatAttribute attribs[] = {
kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
static_cast<CGLPixelFormatAttribute>(0)};
GLint nVirtualScreens = 0;
- CGLChoosePixelFormat(attribs, &pixelFormat, &nVirtualScreens);
+ CGLChoosePixelFormat(attribs, &mPixelFormat, &nVirtualScreens);
- if (pixelFormat == nullptr)
+ if (mPixelFormat == nullptr)
{
return egl::EglNotInitialized() << "Could not create the context's pixel format.";
}
}
- CGLCreateContext(pixelFormat, nullptr, &mContext);
+ CGLCreateContext(mPixelFormat, nullptr, &mContext);
if (mContext == nullptr)
{
return egl::EglNotInitialized() << "Could not create the CGL context.";
@@ -94,7 +93,7 @@
std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLCGL(handle));
functionsGL->initialize(display->getAttributeMap());
- mRenderer.reset(new RendererGL(std::move(functionsGL), display->getAttributeMap()));
+ mRenderer.reset(new RendererCGL(std::move(functionsGL), display->getAttributeMap(), this));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
@@ -316,4 +315,55 @@
// default.
return egl::NoError();
}
+
+class WorkerContextCGL final : public WorkerContext
+{
+ public:
+ WorkerContextCGL(CGLContextObj context);
+ ~WorkerContextCGL() override;
+
+ bool makeCurrent() override;
+ void unmakeCurrent() override;
+
+ private:
+ CGLContextObj mContext;
+};
+
+WorkerContextCGL::WorkerContextCGL(CGLContextObj context) : mContext(context) {}
+
+WorkerContextCGL::~WorkerContextCGL()
+{
+ CGLSetCurrentContext(nullptr);
+ CGLReleaseContext(mContext);
+ mContext = nullptr;
+}
+
+bool WorkerContextCGL::makeCurrent()
+{
+ CGLError error = CGLSetCurrentContext(mContext);
+ if (error != kCGLNoError)
+ {
+ ERR() << "Unable to make gl context current.";
+ return false;
+ }
+ return true;
+}
+
+void WorkerContextCGL::unmakeCurrent()
+{
+ CGLSetCurrentContext(nullptr);
+}
+
+WorkerContext *DisplayCGL::createWorkerContext(std::string *infoLog)
+{
+ CGLContextObj context = nullptr;
+ CGLCreateContext(mPixelFormat, mContext, &context);
+ if (context == nullptr)
+ {
+ *infoLog += "Could not create the CGL context.";
+ return nullptr;
+ }
+
+ return new WorkerContextCGL(context);
+}
}
diff --git a/src/libANGLE/renderer/gl/cgl/RendererCGL.h b/src/libANGLE/renderer/gl/cgl/RendererCGL.h
new file mode 100644
index 0000000..1267d8d
--- /dev/null
+++ b/src/libANGLE/renderer/gl/cgl/RendererCGL.h
@@ -0,0 +1,35 @@
+//
+// Copyright 2019 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.
+//
+
+// RendererCGL.h: implements createWorkerContext for RendererGL.
+
+#ifndef LIBANGLE_RENDERER_GL_CGL_RENDERERCGL_H_
+#define LIBANGLE_RENDERER_GL_CGL_RENDERERCGL_H_
+
+#include "libANGLE/renderer/gl/RendererGL.h"
+
+namespace rx
+{
+
+class DisplayCGL;
+
+class RendererCGL : public RendererGL
+{
+ public:
+ RendererCGL(std::unique_ptr<FunctionsGL> functions,
+ const egl::AttributeMap &attribMap,
+ DisplayCGL *display);
+ ~RendererCGL() override;
+
+ private:
+ WorkerContext *createWorkerContext(std::string *infoLog) override;
+
+ DisplayCGL *mDisplay;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_GL_GLX_RENDERERGLX_H_
diff --git a/src/libANGLE/renderer/gl/cgl/RendererCGL.mm b/src/libANGLE/renderer/gl/cgl/RendererCGL.mm
new file mode 100644
index 0000000..33c8fe3
--- /dev/null
+++ b/src/libANGLE/renderer/gl/cgl/RendererCGL.mm
@@ -0,0 +1,29 @@
+//
+// Copyright 2019 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.
+//
+
+// RendererCGL.mm: Implements the class methods for RendererCGL.
+
+#include "libANGLE/renderer/gl/cgl/RendererCGL.h"
+
+#include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
+
+namespace rx
+{
+
+RendererCGL::RendererCGL(std::unique_ptr<FunctionsGL> functions,
+ const egl::AttributeMap &attribMap,
+ DisplayCGL *display)
+ : RendererGL(std::move(functions), attribMap), mDisplay(display)
+{}
+
+RendererCGL::~RendererCGL() {}
+
+WorkerContext *RendererCGL::createWorkerContext(std::string *infoLog)
+{
+ return mDisplay->createWorkerContext(infoLog);
+}
+
+} // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
index adb5327..1e15078 100644
--- a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
+++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
@@ -9,7 +9,6 @@
#include "libANGLE/renderer/gl/egl/DisplayEGL.h"
#include "libANGLE/renderer/gl/egl/ImageEGL.h"
-#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx
{
@@ -39,7 +38,8 @@
egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes,
- EGLContext *outContext) const
+ EGLContext *outContext,
+ native_egl::AttributeVector *outAttribs) const
{
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
@@ -97,6 +97,7 @@
if (context != EGL_NO_CONTEXT)
{
*outContext = context;
+ *outAttribs = attribList;
return egl::NoError();
}
}
diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.h b/src/libANGLE/renderer/gl/egl/DisplayEGL.h
index 3a90a19..5cc8ba5 100644
--- a/src/libANGLE/renderer/gl/egl/DisplayEGL.h
+++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.h
@@ -11,10 +11,13 @@
#include "libANGLE/renderer/gl/DisplayGL.h"
#include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
+#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx
{
+class WorkerContext;
+
class DisplayEGL : public DisplayGL
{
public:
@@ -32,10 +35,15 @@
virtual void destroyNativeContext(EGLContext context) = 0;
+ virtual WorkerContext *createWorkerContext(std::string *infoLog,
+ EGLContext sharedContext,
+ const native_egl::AttributeVector workerAttribs) = 0;
+
protected:
egl::Error initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes,
- EGLContext *outContext) const;
+ EGLContext *outContext,
+ native_egl::AttributeVector *outAttribs) const;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
diff --git a/src/libANGLE/renderer/gl/egl/RendererEGL.cpp b/src/libANGLE/renderer/gl/egl/RendererEGL.cpp
index cc3d8c7..11cc021 100644
--- a/src/libANGLE/renderer/gl/egl/RendererEGL.cpp
+++ b/src/libANGLE/renderer/gl/egl/RendererEGL.cpp
@@ -14,8 +14,12 @@
RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayEGL *display,
- EGLContext context)
- : RendererGL(std::move(functionsGL), attribMap), mDisplay(display), mContext(context)
+ EGLContext context,
+ const native_egl::AttributeVector attribs)
+ : RendererGL(std::move(functionsGL), attribMap),
+ mDisplay(display),
+ mContext(context),
+ mAttribs(attribs)
{}
RendererEGL::~RendererEGL()
@@ -29,4 +33,9 @@
return mContext;
}
+WorkerContext *RendererEGL::createWorkerContext(std::string *infoLog)
+{
+ return mDisplay->createWorkerContext(infoLog, mContext, mAttribs);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/RendererEGL.h b/src/libANGLE/renderer/gl/egl/RendererEGL.h
index ed81ed6..e1af5e0 100644
--- a/src/libANGLE/renderer/gl/egl/RendererEGL.h
+++ b/src/libANGLE/renderer/gl/egl/RendererEGL.h
@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
#include "libANGLE/renderer/gl/RendererGL.h"
+#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx
{
@@ -21,14 +22,18 @@
RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayEGL *display,
- EGLContext context);
+ EGLContext context,
+ const native_egl::AttributeVector attribs);
~RendererEGL() override;
EGLContext getContext() const;
+ WorkerContext *createWorkerContext(std::string *infoLog) override;
+
private:
DisplayEGL *mDisplay;
EGLContext mContext;
+ const native_egl::AttributeVector mAttribs;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
index d5176fd..4271386 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
@@ -602,7 +602,8 @@
std::shared_ptr<RendererEGL> *outRenderer)
{
EGLContext context = EGL_NO_CONTEXT;
- ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context));
+ native_egl::AttributeVector attribs;
+ ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
if (mEGL->makeCurrent(mDummyPbuffer, context) == EGL_FALSE)
{
@@ -613,7 +614,8 @@
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(mDisplayAttributes);
- outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context));
+ outRenderer->reset(
+ new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs));
CurrentNativeContext ¤tContext = mCurrentNativeContext[std::this_thread::get_id()];
if (makeNewContextCurrent)
@@ -634,4 +636,58 @@
return egl::NoError();
}
+class WorkerContextAndroid final : public WorkerContext
+{
+ public:
+ WorkerContextAndroid(EGLContext context, FunctionsEGL *functions, EGLSurface pbuffer);
+ ~WorkerContextAndroid() override;
+
+ bool makeCurrent() override;
+ void unmakeCurrent() override;
+
+ private:
+ EGLContext mContext;
+ FunctionsEGL *mFunctions;
+ EGLSurface mPbuffer;
+};
+
+WorkerContextAndroid::WorkerContextAndroid(EGLContext context,
+ FunctionsEGL *functions,
+ EGLSurface pbuffer)
+ : mContext(context), mFunctions(functions), mPbuffer(pbuffer)
+{}
+
+WorkerContextAndroid::~WorkerContextAndroid()
+{
+ mFunctions->destroyContext(mContext);
+}
+
+bool WorkerContextAndroid::makeCurrent()
+{
+ if (mFunctions->makeCurrent(mPbuffer, mContext) == EGL_FALSE)
+ {
+ ERR() << "Unable to make the EGL context current.";
+ return false;
+ }
+ return true;
+}
+
+void WorkerContextAndroid::unmakeCurrent()
+{
+ mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+WorkerContext *DisplayAndroid::createWorkerContext(std::string *infoLog,
+ EGLContext sharedContext,
+ const native_egl::AttributeVector workerAttribs)
+{
+ EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
+ if (context == EGL_NO_CONTEXT)
+ {
+ *infoLog += "Unable to create the EGL context.";
+ return nullptr;
+ }
+ return new WorkerContextAndroid(context, mEGL, mDummyPbuffer);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
index 577db2f..028327d 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
@@ -78,6 +78,10 @@
void destroyNativeContext(EGLContext context) override;
+ WorkerContext *createWorkerContext(std::string *infoLog,
+ EGLContext sharedContext,
+ const native_egl::AttributeVector workerAttribs) override;
+
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
diff --git a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
index 0b7ec68..47ed6ce 100644
--- a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
+++ b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
@@ -524,7 +524,8 @@
}
EGLContext context = EGL_NO_CONTEXT;
- ANGLE_TRY(initializeContext(EGL_NO_CONTEXT, display->getAttributeMap(), &context));
+ native_egl::AttributeVector attribs;
+ ANGLE_TRY(initializeContext(EGL_NO_CONTEXT, display->getAttributeMap(), &context, &attribs));
if (!mEGL->makeCurrent(EGL_NO_SURFACE, context))
{
@@ -534,8 +535,8 @@
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(display->getAttributeMap());
- mRenderer.reset(
- new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this, context));
+ mRenderer.reset(new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this,
+ context, attribs));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
@@ -1021,4 +1022,55 @@
return egl::NoError();
}
+class WorkerContextOzone final : public WorkerContext
+{
+ public:
+ WorkerContextOzone(EGLContext context, FunctionsEGL *functions);
+ ~WorkerContextOzone() override;
+
+ bool makeCurrent() override;
+ void unmakeCurrent() override;
+
+ private:
+ EGLContext mContext;
+ FunctionsEGL *mFunctions;
+};
+
+WorkerContextOzone::WorkerContextOzone(EGLContext context, FunctionsEGL *functions)
+ : mContext(context), mFunctions(functions)
+{}
+
+WorkerContextOzone::~WorkerContextOzone()
+{
+ mFunctions->destroyContext(mContext);
+}
+
+bool WorkerContextOzone::makeCurrent()
+{
+ if (mFunctions->makeCurrent(EGL_NO_SURFACE, mContext) == EGL_FALSE)
+ {
+ ERR() << "Unable to make the EGL context current.";
+ return false;
+ }
+ return true;
+}
+
+void WorkerContextOzone::unmakeCurrent()
+{
+ mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+WorkerContext *DisplayOzone::createWorkerContext(std::string *infoLog,
+ EGLContext sharedContext,
+ const native_egl::AttributeVector workerAttribs)
+{
+ EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
+ if (context == EGL_NO_CONTEXT)
+ {
+ *infoLog += "Unable to create the EGL context.";
+ return nullptr;
+ }
+ return new WorkerContextOzone(context, mEGL);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
index 4988595..6f96294 100644
--- a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
+++ b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
@@ -156,6 +156,10 @@
// one required so that the subsequent swapBuffers acts as expected.
void setSwapInterval(EGLSurface drawable, SwapControlData *data);
+ WorkerContext *createWorkerContext(std::string *infoLog,
+ EGLContext sharedContext,
+ const native_egl::AttributeVector workerAttribs) override;
+
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
diff --git a/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp b/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp
index 979fd38..65cd649 100644
--- a/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp
+++ b/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp
@@ -19,8 +19,8 @@
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/ContextGL.h"
-#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h"
+#include "libANGLE/renderer/gl/glx/RendererGLX.h"
#include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
@@ -56,7 +56,9 @@
: DisplayGL(state),
mRequestedVisual(-1),
mContextConfig(nullptr),
+ mVisuals(nullptr),
mContext(nullptr),
+ mSharedContext(nullptr),
mDummyPbuffer(0),
mUsesNewXDisplay(false),
mIsMesa(false),
@@ -228,21 +230,21 @@
visualTemplate.visualid = getGLXFBConfigAttrib(mContextConfig, GLX_VISUAL_ID);
int numVisuals = 0;
- XVisualInfo *visuals =
- XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals);
+ mVisuals = XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals);
if (numVisuals <= 0)
{
return egl::EglNotInitialized() << "Could not get the visual info from the fb config";
}
ASSERT(numVisuals == 1);
- mContext = mGLX.createContext(&visuals[0], nullptr, true);
- XFree(visuals);
+ mContext = mGLX.createContext(&mVisuals[0], nullptr, true);
if (!mContext)
{
return egl::EglNotInitialized() << "Could not create GL context.";
}
+
+ mSharedContext = mGLX.createContext(&mVisuals[0], mContext, True);
}
ASSERT(mContext);
@@ -285,9 +287,22 @@
return egl::EglNotInitialized() << "Intel or NVIDIA OpenGL ES drivers are not supported.";
}
+ if (mSharedContext)
+ {
+ for (unsigned int i = 0; i < RendererGL::getMaxWorkerContexts(); ++i)
+ {
+ glx::Pbuffer workerPbuffer = mGLX.createPbuffer(mContextConfig, dummyPbufferAttribs);
+ if (!workerPbuffer)
+ {
+ return egl::EglNotInitialized() << "Could not create the worker pbuffers.";
+ }
+ mWorkerPbufferPool.push_back(workerPbuffer);
+ }
+ }
+
syncXCommands();
- mRenderer.reset(new RendererGL(std::move(functionsGL), eglAttributes));
+ mRenderer.reset(new RendererGLX(std::move(functionsGL), eglAttributes, this));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
@@ -301,18 +316,36 @@
{
DisplayGL::terminate();
+ if (mVisuals)
+ {
+ XFree(mVisuals);
+ mVisuals = 0;
+ }
+
if (mDummyPbuffer)
{
mGLX.destroyPbuffer(mDummyPbuffer);
mDummyPbuffer = 0;
}
+ for (auto &workerPbuffer : mWorkerPbufferPool)
+ {
+ mGLX.destroyPbuffer(workerPbuffer);
+ }
+ mWorkerPbufferPool.clear();
+
if (mContext)
{
mGLX.destroyContext(mContext);
mContext = nullptr;
}
+ if (mSharedContext)
+ {
+ mGLX.destroyContext(mSharedContext);
+ mSharedContext = nullptr;
+ }
+
mGLX.terminate();
mRenderer.reset();
@@ -811,34 +844,34 @@
egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
const Optional<gl::Version> &version,
int profileMask,
- glx::Context *context) const
+ glx::Context *context)
{
- std::vector<int> attribs;
+ mAttribs.clear();
if (mHasARBCreateContextRobustness)
{
- attribs.push_back(GLX_CONTEXT_FLAGS_ARB);
- attribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
- attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
- attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
+ mAttribs.push_back(GLX_CONTEXT_FLAGS_ARB);
+ mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
+ mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
+ mAttribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
}
if (version.valid())
{
- attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
- attribs.push_back(version.value().major);
+ mAttribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
+ mAttribs.push_back(version.value().major);
- attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
- attribs.push_back(version.value().minor);
+ mAttribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
+ mAttribs.push_back(version.value().minor);
}
if (profileMask != 0 && mHasARBCreateContextProfile)
{
- attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
- attribs.push_back(profileMask);
+ mAttribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
+ mAttribs.push_back(profileMask);
}
- attribs.push_back(None);
+ mAttribs.push_back(None);
// When creating a context with glXCreateContextAttribsARB, a variety of X11 errors can
// be generated. To prevent these errors from crashing our process, we simply ignore
@@ -847,14 +880,95 @@
// (the error handler is NOT per-display).
XSync(mXDisplay, False);
auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
- *context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, attribs.data());
+ *context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, mAttribs.data());
XSetErrorHandler(oldErrorHandler);
if (!*context)
{
return egl::EglNotInitialized() << "Could not create GL context.";
}
+
+ mSharedContext = mGLX.createContextAttribsARB(mContextConfig, mContext, True, mAttribs.data());
+
return egl::NoError();
}
+class WorkerContextGLX final : public WorkerContext
+{
+ public:
+ WorkerContextGLX(glx::Context context, FunctionsGLX *functions, glx::Pbuffer buffer);
+ ~WorkerContextGLX() override;
+
+ bool makeCurrent() override;
+ void unmakeCurrent() override;
+
+ private:
+ glx::Context mContext;
+ FunctionsGLX *mFunctions;
+ glx::Pbuffer mBuffer;
+};
+
+WorkerContextGLX::WorkerContextGLX(glx::Context context,
+ FunctionsGLX *functions,
+ glx::Pbuffer buffer)
+ : mContext(context), mFunctions(functions), mBuffer(buffer)
+{}
+
+WorkerContextGLX::~WorkerContextGLX()
+{
+ mFunctions->destroyContext(mContext);
+ mFunctions->destroyPbuffer(mBuffer);
+}
+
+bool WorkerContextGLX::makeCurrent()
+{
+ Bool result = mFunctions->makeCurrent(mBuffer, mContext);
+ if (result != True)
+ {
+ ERR() << "Unable to make the GLX context current.";
+ return false;
+ }
+ return true;
+}
+
+void WorkerContextGLX::unmakeCurrent()
+{
+ mFunctions->makeCurrent(0, nullptr);
+}
+
+WorkerContext *DisplayGLX::createWorkerContext(std::string *infoLog)
+{
+ if (!mSharedContext)
+ {
+ *infoLog += "No shared context.";
+ return nullptr;
+ }
+ if (mWorkerPbufferPool.empty())
+ {
+ *infoLog += "No worker pbuffers.";
+ return nullptr;
+ }
+ glx::Context context = nullptr;
+ if (mHasARBCreateContext)
+ {
+ context =
+ mGLX.createContextAttribsARB(mContextConfig, mSharedContext, True, mAttribs.data());
+ }
+ else
+ {
+ context = mGLX.createContext(&mVisuals[0], mSharedContext, True);
+ }
+
+ if (!context)
+ {
+ *infoLog += "Unable to create the glx context.";
+ return nullptr;
+ }
+
+ glx::Pbuffer workerPbuffer = mWorkerPbufferPool.back();
+ mWorkerPbufferPool.pop_back();
+
+ return new WorkerContextGLX(context, &mGLX, workerPbuffer);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/glx/DisplayGLX.h b/src/libANGLE/renderer/gl/glx/DisplayGLX.h
index 5b5d536..32b27f1 100644
--- a/src/libANGLE/renderer/gl/glx/DisplayGLX.h
+++ b/src/libANGLE/renderer/gl/glx/DisplayGLX.h
@@ -20,6 +20,7 @@
{
class FunctionsGLX;
+class WorkerContext;
// State-tracking data for the swap control to allow DisplayGLX to remember per
// drawable information for swap control.
@@ -97,6 +98,8 @@
bool isValidWindowVisualId(unsigned long visualId) const;
+ WorkerContext *createWorkerContext(std::string *infoLog);
+
private:
egl::Error initializeContext(glx::FBConfig config,
const egl::AttributeMap &eglAttributes,
@@ -111,7 +114,7 @@
egl::Error createContextAttribs(glx::FBConfig,
const Optional<gl::Version> &version,
int profileMask,
- glx::Context *context) const;
+ glx::Context *context);
std::shared_ptr<RendererGL> mRenderer;
@@ -119,10 +122,15 @@
EGLint mRequestedVisual;
glx::FBConfig mContextConfig;
+ std::vector<int> mAttribs;
+ XVisualInfo *mVisuals;
glx::Context mContext;
+ glx::Context mSharedContext;
// A pbuffer the context is current on during ANGLE initialization
glx::Pbuffer mDummyPbuffer;
+ std::vector<glx::Pbuffer> mWorkerPbufferPool;
+
bool mUsesNewXDisplay;
bool mIsMesa;
bool mHasMultisample;
diff --git a/src/libANGLE/renderer/gl/glx/RendererGLX.cpp b/src/libANGLE/renderer/gl/glx/RendererGLX.cpp
new file mode 100644
index 0000000..fa47ab7
--- /dev/null
+++ b/src/libANGLE/renderer/gl/glx/RendererGLX.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright 2019 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.
+//
+
+// RendererGLX.cpp: Implements the class methods for RendererGLX.
+
+#include "libANGLE/renderer/gl/glx/RendererGLX.h"
+
+#include "libANGLE/renderer/gl/glx/DisplayGLX.h"
+
+namespace rx
+{
+
+RendererGLX::RendererGLX(std::unique_ptr<FunctionsGL> functions,
+ const egl::AttributeMap &attribMap,
+ DisplayGLX *display)
+ : RendererGL(std::move(functions), attribMap), mDisplay(display)
+{}
+
+RendererGLX::~RendererGLX() {}
+
+WorkerContext *RendererGLX::createWorkerContext(std::string *infoLog)
+{
+ return mDisplay->createWorkerContext(infoLog);
+}
+
+} // namespace rx
diff --git a/src/libANGLE/renderer/gl/glx/RendererGLX.h b/src/libANGLE/renderer/gl/glx/RendererGLX.h
new file mode 100644
index 0000000..c337b3d
--- /dev/null
+++ b/src/libANGLE/renderer/gl/glx/RendererGLX.h
@@ -0,0 +1,35 @@
+//
+// Copyright 2019 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.
+//
+
+// RendererGLX.h: implements createWorkerContext for RendererGL.
+
+#ifndef LIBANGLE_RENDERER_GL_GLX_RENDERERGLX_H_
+#define LIBANGLE_RENDERER_GL_GLX_RENDERERGLX_H_
+
+#include "libANGLE/renderer/gl/RendererGL.h"
+
+namespace rx
+{
+
+class DisplayGLX;
+
+class RendererGLX : public RendererGL
+{
+ public:
+ RendererGLX(std::unique_ptr<FunctionsGL> functions,
+ const egl::AttributeMap &attribMap,
+ DisplayGLX *display);
+ ~RendererGLX() override;
+
+ private:
+ WorkerContext *createWorkerContext(std::string *infoLog) override;
+
+ DisplayGLX *mDisplay;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_GL_GLX_RENDERERGLX_H_
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 44d0f8a..1e3310d 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -1442,6 +1442,8 @@
workarounds->unsizedsRGBReadPixelsDoesntTransform = IsAndroid() && IsQualcomm(vendor);
workarounds->queryCounterBitsGeneratesErrors = IsNexus5X(vendor, device);
+
+ workarounds->dontRelinkProgramsInParallel = IsAndroid() || (IsWindows() && IsIntel(vendor));
}
void ApplyWorkarounds(const FunctionsGL *functions, gl::Workarounds *workarounds)
diff --git a/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp b/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
index d086f5b..5baa08a 100644
--- a/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
+++ b/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
@@ -34,6 +34,33 @@
namespace rx
{
+namespace
+{
+
+std::string GetErrorMessage()
+{
+ DWORD errorCode = GetLastError();
+ LPSTR messageBuffer = nullptr;
+ size_t size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
+ std::string message(messageBuffer, size);
+ if (size == 0)
+ {
+ std::ostringstream stream;
+ stream << "Failed to get the error message for '" << errorCode << "' due to the error '"
+ << GetLastError() << "'";
+ message = stream.str();
+ }
+ if (messageBuffer != nullptr)
+ {
+ LocalFree(messageBuffer);
+ }
+ return message;
+}
+
+} // anonymous namespace
+
class FunctionsGLWindows : public FunctionsGL
{
public:
@@ -78,7 +105,9 @@
mDxgiModule(nullptr),
mD3d11Module(nullptr),
mD3D11DeviceHandle(nullptr),
- mD3D11Device(nullptr)
+ mD3D11Device(nullptr),
+ mHasWorkerContexts(true),
+ mUseARBShare(true)
{}
DisplayWGL::~DisplayWGL() {}
@@ -264,6 +293,13 @@
return egl::EglNotInitialized() << "Intel OpenGL ES drivers are not supported.";
}
+ // Using worker contexts is not currently supported due to bugs in the driver.
+ // http://anglebug.com/3031
+ if (IsAMD(vendor))
+ {
+ mHasWorkerContexts = false;
+ }
+
// Create DXGI swap chains for windows that come from other processes. Windows is unable to
// SetPixelFormat on windows from other processes when a sandbox is enabled.
HDC nativeDisplay = display->getNativeDisplayId();
@@ -753,7 +789,10 @@
mFunctionsWGL->deleteContext(context);
}
-HGLRC DisplayWGL::initializeContextAttribs(const egl::AttributeMap &eglAttributes) const
+HGLRC DisplayWGL::initializeContextAttribs(const egl::AttributeMap &eglAttributes,
+ HGLRC &sharedContext,
+ bool &useARBShare,
+ std::vector<int> &workerContextAttribs) const
{
EGLint requestedDisplayType = static_cast<EGLint>(
eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
@@ -772,7 +811,8 @@
{
profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
}
- return createContextAttribs(requestedVersion, profileMask);
+ return createContextAttribs(requestedVersion, profileMask, sharedContext, useARBShare,
+ workerContextAttribs);
}
// Try all the GL version in order as a workaround for Mesa context creation where the driver
@@ -789,7 +829,8 @@
profileFlag |= WGL_CONTEXT_ES_PROFILE_BIT_EXT;
}
- HGLRC context = createContextAttribs(info.version, profileFlag);
+ HGLRC context = createContextAttribs(info.version, profileFlag, sharedContext, useARBShare,
+ workerContextAttribs);
if (context != nullptr)
{
return context;
@@ -799,7 +840,11 @@
return nullptr;
}
-HGLRC DisplayWGL::createContextAttribs(const gl::Version &version, int profileMask) const
+HGLRC DisplayWGL::createContextAttribs(const gl::Version &version,
+ int profileMask,
+ HGLRC &sharedContext,
+ bool &useARBShare,
+ std::vector<int> &workerContextAttribs) const
{
std::vector<int> attribs;
@@ -825,16 +870,29 @@
attribs.push_back(0);
attribs.push_back(0);
+ HGLRC context = mFunctionsWGL->createContextAttribsARB(mDeviceContext, nullptr, &attribs[0]);
- return mFunctionsWGL->createContextAttribsARB(mDeviceContext, nullptr, &attribs[0]);
+ // This shared context is never made current. It is safer than the main context to be used as
+ // a seed to create worker contexts from.
+ // It seems a WGL restriction not mentioned in MSDN, but some posts revealed it.
+ // https://www.opengl.org/discussion_boards/showthread.php/152648-wglShareLists-failing
+ // https://github.com/glfw/glfw/issues/402
+ sharedContext = mFunctionsWGL->createContextAttribsARB(mDeviceContext, context, &attribs[0]);
+ workerContextAttribs = attribs;
+ useARBShare = true;
+ return context;
}
egl::Error DisplayWGL::createRenderer(std::shared_ptr<RendererWGL> *outRenderer)
{
HGLRC context = nullptr;
+ HGLRC sharedContext = nullptr;
+ std::vector<int> workerContextAttribs;
+
if (mFunctionsWGL->createContextAttribsARB)
{
- context = initializeContextAttribs(mDisplayAttributes);
+ context = initializeContextAttribs(mDisplayAttributes, sharedContext, mUseARBShare,
+ workerContextAttribs);
}
// If wglCreateContextAttribsARB is unavailable or failed, try the standard wglCreateContext
@@ -847,7 +905,19 @@
if (!context)
{
return egl::EglNotInitialized()
- << "Failed to create a WGL context for the intermediate OpenGL window.";
+ << "Failed to create a WGL context for the intermediate OpenGL window."
+ << GetErrorMessage();
+ }
+
+ if (!sharedContext)
+ {
+ sharedContext = mFunctionsWGL->createContext(mDeviceContext);
+ if (!mFunctionsWGL->shareLists(context, sharedContext))
+ {
+ mFunctionsWGL->deleteContext(sharedContext);
+ sharedContext = nullptr;
+ }
+ mUseARBShare = false;
}
if (!mFunctionsWGL->makeCurrent(mDeviceContext, context))
@@ -862,8 +932,136 @@
new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress));
functionsGL->initialize(mDisplayAttributes);
- outRenderer->reset(new RendererWGL(std::move(functionsGL), mDisplayAttributes, this, context));
+ outRenderer->reset(new RendererWGL(std::move(functionsGL), mDisplayAttributes, this, context,
+ sharedContext, workerContextAttribs));
return egl::NoError();
}
+
+class WorkerContextWGL final : public WorkerContext
+{
+ public:
+ WorkerContextWGL(FunctionsWGL *functions,
+ HPBUFFERARB pbuffer,
+ HDC deviceContext,
+ HGLRC context);
+ ~WorkerContextWGL() override;
+
+ bool makeCurrent() override;
+ void unmakeCurrent() override;
+
+ private:
+ FunctionsWGL *mFunctionsWGL;
+ HPBUFFERARB mPbuffer;
+ HDC mDeviceContext;
+ HGLRC mContext;
+};
+
+WorkerContextWGL::WorkerContextWGL(FunctionsWGL *functions,
+ HPBUFFERARB pbuffer,
+ HDC deviceContext,
+ HGLRC context)
+ : mFunctionsWGL(functions), mPbuffer(pbuffer), mDeviceContext(deviceContext), mContext(context)
+{}
+
+WorkerContextWGL::~WorkerContextWGL()
+{
+ mFunctionsWGL->makeCurrent(mDeviceContext, nullptr);
+ mFunctionsWGL->deleteContext(mContext);
+ mFunctionsWGL->releasePbufferDCARB(mPbuffer, mDeviceContext);
+ mFunctionsWGL->destroyPbufferARB(mPbuffer);
+}
+
+bool WorkerContextWGL::makeCurrent()
+{
+ bool result = mFunctionsWGL->makeCurrent(mDeviceContext, mContext);
+ if (!result)
+ {
+ ERR() << GetErrorMessage();
+ }
+ return result;
+}
+
+void WorkerContextWGL::unmakeCurrent()
+{
+ mFunctionsWGL->makeCurrent(mDeviceContext, nullptr);
+}
+
+WorkerContext *DisplayWGL::createWorkerContext(std::string *infoLog,
+ HGLRC sharedContext,
+ const std::vector<int> &workerContextAttribs)
+{
+ if (!mHasWorkerContexts)
+ {
+ *infoLog += "Has no WorkerContext support.";
+ return nullptr;
+ }
+ if (!sharedContext)
+ {
+ *infoLog += "Unable to create the shared context.";
+ return nullptr;
+ }
+
+ HPBUFFERARB workerPbuffer = nullptr;
+ HDC workerDeviceContext = nullptr;
+ HGLRC workerContext = nullptr;
+
+#define CLEANUP_ON_ERROR() \
+ if (workerContext) \
+ { \
+ mFunctionsWGL->deleteContext(workerContext); \
+ } \
+ if (workerDeviceContext) \
+ { \
+ mFunctionsWGL->releasePbufferDCARB(workerPbuffer, workerDeviceContext); \
+ } \
+ if (workerPbuffer) \
+ { \
+ mFunctionsWGL->destroyPbufferARB(workerPbuffer); \
+ }
+
+ const int attribs[] = {0, 0};
+ workerPbuffer = mFunctionsWGL->createPbufferARB(mDeviceContext, mPixelFormat, 1, 1, attribs);
+ if (!workerPbuffer)
+ {
+ *infoLog += GetErrorMessage();
+ return nullptr;
+ }
+
+ workerDeviceContext = mFunctionsWGL->getPbufferDCARB(workerPbuffer);
+ if (!workerDeviceContext)
+ {
+ *infoLog += GetErrorMessage();
+ CLEANUP_ON_ERROR();
+ return nullptr;
+ }
+
+ if (mUseARBShare)
+ {
+ workerContext = mFunctionsWGL->createContextAttribsARB(mDeviceContext, sharedContext,
+ &workerContextAttribs[0]);
+ }
+ else
+ {
+ workerContext = mFunctionsWGL->createContext(workerDeviceContext);
+ }
+ if (!workerContext)
+ {
+ GetErrorMessage();
+ CLEANUP_ON_ERROR();
+ return nullptr;
+ }
+
+ if (!mUseARBShare && !mFunctionsWGL->shareLists(sharedContext, workerContext))
+ {
+ GetErrorMessage();
+ CLEANUP_ON_ERROR();
+ return nullptr;
+ }
+
+#undef CLEANUP_ON_ERROR
+
+ return new WorkerContextWGL(mFunctionsWGL, workerPbuffer, workerDeviceContext, workerContext);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/wgl/DisplayWGL.h b/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
index f7bd634..2decba1 100644
--- a/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
+++ b/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
@@ -9,18 +9,19 @@
#ifndef LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_
#define LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_
+#include <thread>
+#include <unordered_map>
+
#include "libANGLE/renderer/gl/DisplayGL.h"
#include <GL/wglext.h>
-#include <thread>
-#include <unordered_map>
-
namespace rx
{
class FunctionsWGL;
class RendererWGL;
+class WorkerContext;
class DisplayWGL : public DisplayGL
{
@@ -80,6 +81,10 @@
void destroyNativeContext(HGLRC context);
+ WorkerContext *createWorkerContext(std::string *infoLog,
+ HGLRC sharedContext,
+ const std::vector<int> &workerContextAttribs);
+
private:
egl::Error initializeImpl(egl::Display *display);
void destroy();
@@ -91,8 +96,15 @@
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
- HGLRC initializeContextAttribs(const egl::AttributeMap &eglAttributes) const;
- HGLRC createContextAttribs(const gl::Version &version, int profileMask) const;
+ HGLRC initializeContextAttribs(const egl::AttributeMap &eglAttributes,
+ HGLRC &sharedContext,
+ bool &useARBShare,
+ std::vector<int> &workerContextAttribs) const;
+ HGLRC createContextAttribs(const gl::Version &version,
+ int profileMask,
+ HGLRC &sharedContext,
+ bool &useARBShare,
+ std::vector<int> &workerContextAttribs) const;
egl::Error createRenderer(std::shared_ptr<RendererWGL> *outRenderer);
@@ -132,6 +144,9 @@
size_t refCount;
};
std::map<IUnknown *, D3DObjectHandle> mRegisteredD3DDevices;
+
+ bool mHasWorkerContexts;
+ bool mUseARBShare;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/wgl/RendererWGL.cpp b/src/libANGLE/renderer/gl/wgl/RendererWGL.cpp
index 6442524..ce15031 100644
--- a/src/libANGLE/renderer/gl/wgl/RendererWGL.cpp
+++ b/src/libANGLE/renderer/gl/wgl/RendererWGL.cpp
@@ -14,12 +14,22 @@
RendererWGL::RendererWGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayWGL *display,
- HGLRC context)
- : RendererGL(std::move(functionsGL), attribMap), mDisplay(display), mContext(context)
+ HGLRC context,
+ HGLRC sharedContext,
+ const std::vector<int> workerContextAttribs)
+ : RendererGL(std::move(functionsGL), attribMap),
+ mDisplay(display),
+ mContext(context),
+ mSharedContext(sharedContext),
+ mWorkerContextAttribs(workerContextAttribs)
{}
RendererWGL::~RendererWGL()
{
+ if (mSharedContext != nullptr)
+ {
+ mDisplay->destroyNativeContext(mSharedContext);
+ }
mDisplay->destroyNativeContext(mContext);
mContext = nullptr;
}
@@ -29,4 +39,9 @@
return mContext;
}
+WorkerContext *RendererWGL::createWorkerContext(std::string *infoLog)
+{
+ return mDisplay->createWorkerContext(infoLog, mSharedContext, mWorkerContextAttribs);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/wgl/RendererWGL.h b/src/libANGLE/renderer/gl/wgl/RendererWGL.h
index 59cf153..25aa4dc 100644
--- a/src/libANGLE/renderer/gl/wgl/RendererWGL.h
+++ b/src/libANGLE/renderer/gl/wgl/RendererWGL.h
@@ -22,14 +22,19 @@
RendererWGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayWGL *display,
- HGLRC context);
+ HGLRC context,
+ HGLRC sharedContext,
+ const std::vector<int> workerContextAttribs);
~RendererWGL() override;
HGLRC getContext() const;
private:
+ WorkerContext *createWorkerContext(std::string *infoLog) override;
DisplayWGL *mDisplay;
HGLRC mContext;
+ HGLRC mSharedContext;
+ const std::vector<int> mWorkerContextAttribs;
};
} // namespace rx
diff --git a/src/libGLESv2.gni b/src/libGLESv2.gni
index 9356820..d2e9e6f 100644
--- a/src/libGLESv2.gni
+++ b/src/libGLESv2.gni
@@ -673,6 +673,8 @@
"src/libANGLE/renderer/gl/glx/DisplayGLX.h",
"src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp",
"src/libANGLE/renderer/gl/glx/FunctionsGLX.h",
+ "src/libANGLE/renderer/gl/glx/RendererGLX.h",
+ "src/libANGLE/renderer/gl/glx/RendererGLX.cpp",
"src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp",
"src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h",
"src/libANGLE/renderer/gl/glx/SurfaceGLX.h",
@@ -730,6 +732,8 @@
"src/libANGLE/renderer/gl/cgl/DisplayCGL.h",
"src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.mm",
"src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h",
+ "src/libANGLE/renderer/gl/cgl/RendererCGL.mm",
+ "src/libANGLE/renderer/gl/cgl/RendererCGL.h",
"src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm",
"src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h",
"src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm",
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 6d35cb2..dc5307b 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -1912,7 +1912,9 @@
TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters)
{
std::stringstream vertexShaderStream;
- const unsigned int paramCount = 1024u;
+ // This fails on Macos if the number of parameters is larger than 978 when linking in parallel.
+ // http://anglebug.com/3047
+ const unsigned int paramCount = (IsOSX() ? 978u : 1024u);
vertexShaderStream << "#version 300 es\n"
"precision highp float;\n"
diff --git a/src/tests/perf_tests/LinkProgramPerfTest.cpp b/src/tests/perf_tests/LinkProgramPerfTest.cpp
index 78dafcf..59cb0ac 100644
--- a/src/tests/perf_tests/LinkProgramPerfTest.cpp
+++ b/src/tests/perf_tests/LinkProgramPerfTest.cpp
@@ -19,7 +19,7 @@
namespace
{
-enum class LinkProgramOption
+enum class TaskOption
{
CompileOnly,
CompileAndLink,
@@ -27,9 +27,17 @@
Unspecified
};
+enum class ThreadOption
+{
+ SingleThread,
+ MultiThread,
+
+ Unspecified
+};
+
struct LinkProgramParams final : public RenderTestParams
{
- LinkProgramParams(LinkProgramOption optionIn)
+ LinkProgramParams(TaskOption taskOptionIn, ThreadOption threadOptionIn)
{
iterationsPerStep = 1;
@@ -37,7 +45,8 @@
minorVersion = 0;
windowWidth = 256;
windowHeight = 256;
- option = optionIn;
+ taskOption = taskOptionIn;
+ threadOption = threadOptionIn;
}
std::string suffix() const override
@@ -45,10 +54,23 @@
std::stringstream strstr;
strstr << RenderTestParams::suffix();
- if (option == LinkProgramOption::CompileOnly)
+ 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)
{
@@ -58,7 +80,8 @@
return strstr.str();
}
- LinkProgramOption option;
+ TaskOption taskOption;
+ ThreadOption threadOption;
};
std::ostream &operator<<(std::ostream &os, const LinkProgramParams ¶ms)
@@ -85,6 +108,11 @@
void LinkProgramBenchmark::initializeBenchmark()
{
+ if (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)}};
@@ -117,7 +145,7 @@
ASSERT_NE(0u, vs);
ASSERT_NE(0u, fs);
- if (GetParam().option == LinkProgramOption::CompileOnly)
+ if (GetParam().taskOption == TaskOption::CompileOnly)
{
glDeleteShader(vs);
glDeleteShader(fs);
@@ -146,30 +174,30 @@
using namespace egl_platform;
-LinkProgramParams LinkProgramD3D11Params(LinkProgramOption option)
+LinkProgramParams LinkProgramD3D11Params(TaskOption taskOption, ThreadOption threadOption)
{
- LinkProgramParams params(option);
+ LinkProgramParams params(taskOption, threadOption);
params.eglParameters = D3D11();
return params;
}
-LinkProgramParams LinkProgramD3D9Params(LinkProgramOption option)
+LinkProgramParams LinkProgramD3D9Params(TaskOption taskOption, ThreadOption threadOption)
{
- LinkProgramParams params(option);
+ LinkProgramParams params(taskOption, threadOption);
params.eglParameters = D3D9();
return params;
}
-LinkProgramParams LinkProgramOpenGLOrGLESParams(LinkProgramOption option)
+LinkProgramParams LinkProgramOpenGLOrGLESParams(TaskOption taskOption, ThreadOption threadOption)
{
- LinkProgramParams params(option);
+ LinkProgramParams params(taskOption, threadOption);
params.eglParameters = OPENGL_OR_GLES(false);
return params;
}
-LinkProgramParams LinkProgramVulkanParams(LinkProgramOption option)
+LinkProgramParams LinkProgramVulkanParams(TaskOption taskOption, ThreadOption threadOption)
{
- LinkProgramParams params(option);
+ LinkProgramParams params(taskOption, threadOption);
params.eglParameters = VULKAN();
return params;
}
@@ -179,14 +207,23 @@
run();
}
-ANGLE_INSTANTIATE_TEST(LinkProgramBenchmark,
- LinkProgramD3D11Params(LinkProgramOption::CompileOnly),
- LinkProgramD3D9Params(LinkProgramOption::CompileOnly),
- LinkProgramOpenGLOrGLESParams(LinkProgramOption::CompileOnly),
- LinkProgramVulkanParams(LinkProgramOption::CompileOnly),
- LinkProgramD3D11Params(LinkProgramOption::CompileAndLink),
- LinkProgramD3D9Params(LinkProgramOption::CompileAndLink),
- LinkProgramOpenGLOrGLESParams(LinkProgramOption::CompileAndLink),
- LinkProgramVulkanParams(LinkProgramOption::CompileAndLink));
+ANGLE_INSTANTIATE_TEST(
+ LinkProgramBenchmark,
+ LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
+ LinkProgramD3D9Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
+ LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
+ LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
+ LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
+ LinkProgramD3D9Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
+ LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
+ LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
+ LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::SingleThread),
+ LinkProgramD3D9Params(TaskOption::CompileOnly, ThreadOption::SingleThread),
+ LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
+ LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
+ LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::SingleThread),
+ LinkProgramD3D9Params(TaskOption::CompileAndLink, ThreadOption::SingleThread),
+ LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::SingleThread),
+ LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::SingleThread));
} // anonymous namespace