Commit a100d8f4 by jchen10 Committed by Commit Bot

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: 's avatarGeoff Lang <geofflang@chromium.org>
parent bb4be1ad
...@@ -1098,6 +1098,7 @@ void Program::pathFragmentInputGen(GLint index, ...@@ -1098,6 +1098,7 @@ void Program::pathFragmentInputGen(GLint index,
// The code gets compiled into binaries. // The code gets compiled into binaries.
angle::Result Program::link(const Context *context) angle::Result Program::link(const Context *context)
{ {
ASSERT(mLinkResolved);
const auto &data = context->getState(); const auto &data = context->getState();
auto *platform = ANGLEPlatformCurrent(); auto *platform = ANGLEPlatformCurrent();
......
...@@ -108,17 +108,20 @@ class ScopedExit final : angle::NonCopyable ...@@ -108,17 +108,20 @@ class ScopedExit final : angle::NonCopyable
std::function<void()> mExit; std::function<void()> mExit;
}; };
using CompileImplFunctor = std::function<void(const std::string &)>;
class CompileTask : public angle::Closure class CompileTask : public angle::Closure
{ {
public: public:
CompileTask(ShHandle handle, CompileTask(ShHandle handle,
std::string &&sourcePath, std::string &&sourcePath,
std::string &&source, std::string &&source,
ShCompileOptions options) ShCompileOptions options,
CompileImplFunctor &&functor)
: mHandle(handle), : mHandle(handle),
mSourcePath(sourcePath), mSourcePath(sourcePath),
mSource(source), mSource(source),
mOptions(options), mOptions(options),
mCompileImplFunctor(functor),
mResult(false) mResult(false)
{} {}
void operator()() override void operator()() override
...@@ -130,6 +133,10 @@ class CompileTask : public angle::Closure ...@@ -130,6 +133,10 @@ class CompileTask : public angle::Closure
} }
srcStrings.push_back(mSource.c_str()); srcStrings.push_back(mSource.c_str());
mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions); mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions);
if (mResult)
{
mCompileImplFunctor(sh::GetObjectCode(mHandle));
}
} }
bool getResult() { return mResult; } bool getResult() { return mResult; }
...@@ -138,6 +145,7 @@ class CompileTask : public angle::Closure ...@@ -138,6 +145,7 @@ class CompileTask : public angle::Closure
std::string mSourcePath; std::string mSourcePath;
std::string mSource; std::string mSource;
ShCompileOptions mOptions; ShCompileOptions mOptions;
CompileImplFunctor mCompileImplFunctor;
bool mResult; bool mResult;
}; };
...@@ -385,9 +393,21 @@ void Shader::compile(const Context *context) ...@@ -385,9 +393,21 @@ void Shader::compile(const Context *context)
ASSERT(compilerHandle); ASSERT(compilerHandle);
mCompilerResourcesString = mShCompilerInstance.getBuiltinResourcesString(); mCompilerResourcesString = mShCompilerInstance.getBuiltinResourcesString();
mCompileTask = std::make_shared<CompileTask>(compilerHandle, std::move(sourcePath),
std::move(source), options);
mWorkerPool = context->getWorkerThreadPool(); 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); mCompileEvent = mWorkerPool->postWorkerTask(mCompileTask);
} }
......
...@@ -49,6 +49,7 @@ class SingleThreadedWorkerPool final : public WorkerThreadPool ...@@ -49,6 +49,7 @@ class SingleThreadedWorkerPool final : public WorkerThreadPool
public: public:
std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override; std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
void setMaxThreads(size_t maxThreads) override; void setMaxThreads(size_t maxThreads) override;
bool isAsync() override;
}; };
// SingleThreadedWorkerPool implementation. // SingleThreadedWorkerPool implementation.
...@@ -61,6 +62,11 @@ std::shared_ptr<WaitableEvent> SingleThreadedWorkerPool::postWorkerTask( ...@@ -61,6 +62,11 @@ std::shared_ptr<WaitableEvent> SingleThreadedWorkerPool::postWorkerTask(
void SingleThreadedWorkerPool::setMaxThreads(size_t maxThreads) {} void SingleThreadedWorkerPool::setMaxThreads(size_t maxThreads) {}
bool SingleThreadedWorkerPool::isAsync()
{
return false;
}
#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) #if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
class AsyncWaitableEvent final : public WaitableEvent class AsyncWaitableEvent final : public WaitableEvent
{ {
...@@ -120,6 +126,7 @@ class AsyncWorkerPool final : public WorkerThreadPool ...@@ -120,6 +126,7 @@ class AsyncWorkerPool final : public WorkerThreadPool
std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override; std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
void setMaxThreads(size_t maxThreads) override; void setMaxThreads(size_t maxThreads) override;
bool isAsync() override;
private: private:
void checkToRunPendingTasks(); void checkToRunPendingTasks();
...@@ -156,6 +163,11 @@ void AsyncWorkerPool::setMaxThreads(size_t maxThreads) ...@@ -156,6 +163,11 @@ void AsyncWorkerPool::setMaxThreads(size_t maxThreads)
checkToRunPendingTasks(); checkToRunPendingTasks();
} }
bool AsyncWorkerPool::isAsync()
{
return true;
}
void AsyncWorkerPool::checkToRunPendingTasks() void AsyncWorkerPool::checkToRunPendingTasks()
{ {
std::lock_guard<std::mutex> lock(mMutex); std::lock_guard<std::mutex> lock(mMutex);
......
...@@ -68,6 +68,8 @@ class WorkerThreadPool : angle::NonCopyable ...@@ -68,6 +68,8 @@ class WorkerThreadPool : angle::NonCopyable
virtual std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) = 0; virtual std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) = 0;
virtual void setMaxThreads(size_t maxThreads) = 0; virtual void setMaxThreads(size_t maxThreads) = 0;
virtual bool isAsync() = 0;
}; };
} // namespace angle } // namespace angle
......
...@@ -53,13 +53,8 @@ ...@@ -53,13 +53,8 @@
#endif #endif
// Controls if our threading code uses std::async or falls back to single-threaded operations. // 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_STD_ASYNC_WORKERS)
# if defined(ANGLE_PLATFORM_WINDOWS) # define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED
# define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED
# else
# define ANGLE_STD_ASYNC_WORKERS ANGLE_DISABLED
# endif // defined(ANGLE_PLATFORM_WINDOWS)
#endif // !defined(ANGLE_STD_ASYNC_WORKERS) #endif // !defined(ANGLE_STD_ASYNC_WORKERS)
// Force thread safety in all of ANGLE by locking a global mutex in every ANGLE entry point. // Force thread safety in all of ANGLE by locking a global mutex in every ANGLE entry point.
......
...@@ -27,6 +27,10 @@ class ShaderImpl : angle::NonCopyable ...@@ -27,6 +27,10 @@ class ShaderImpl : angle::NonCopyable
virtual ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context, virtual ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream, std::stringstream *sourceStream,
std::string *sourcePath) = 0; 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. // Returns success for compiling on the driver. Returns success.
virtual bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) = 0; virtual bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) = 0;
......
...@@ -55,13 +55,13 @@ ShaderImpl *ContextGL::createShader(const gl::ShaderState &data) ...@@ -55,13 +55,13 @@ ShaderImpl *ContextGL::createShader(const gl::ShaderState &data)
const FunctionsGL *functions = getFunctions(); const FunctionsGL *functions = getFunctions();
GLuint shader = functions->createShader(ToGLenum(data.getShaderType())); 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) ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
{ {
return new ProgramGL(data, getFunctions(), getWorkaroundsGL(), getStateManager(), return new ProgramGL(data, getFunctions(), getWorkaroundsGL(), getStateManager(),
getExtensions().pathRendering); getExtensions().pathRendering, mRenderer);
} }
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data) FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
......
...@@ -228,6 +228,7 @@ class ContextGL : public ContextImpl ...@@ -228,6 +228,7 @@ class ContextGL : public ContextImpl
angle::Result setDrawIndirectState(const gl::Context *context); angle::Result setDrawIndirectState(const gl::Context *context);
protected:
std::shared_ptr<RendererGL> mRenderer; std::shared_ptr<RendererGL> mRenderer;
}; };
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/Uniform.h" #include "libANGLE/Uniform.h"
#include "libANGLE/WorkerThread.h"
#include "libANGLE/queryconversions.h" #include "libANGLE/queryconversions.h"
#include "libANGLE/renderer/gl/ContextGL.h" #include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/ShaderGL.h" #include "libANGLE/renderer/gl/ShaderGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h" #include "libANGLE/renderer/gl/WorkaroundsGL.h"
...@@ -31,14 +33,17 @@ ProgramGL::ProgramGL(const gl::ProgramState &data, ...@@ -31,14 +33,17 @@ ProgramGL::ProgramGL(const gl::ProgramState &data,
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
StateManagerGL *stateManager, StateManagerGL *stateManager,
bool enablePathRendering) bool enablePathRendering,
const std::shared_ptr<RendererGL> &renderer)
: ProgramImpl(data), : ProgramImpl(data),
mFunctions(functions), mFunctions(functions),
mWorkarounds(workarounds), mWorkarounds(workarounds),
mStateManager(stateManager), mStateManager(stateManager),
mEnablePathRendering(enablePathRendering), mEnablePathRendering(enablePathRendering),
mMultiviewBaseViewLayerIndexUniformLocation(-1), mMultiviewBaseViewLayerIndexUniformLocation(-1),
mProgramID(0) mProgramID(0),
mRenderer(renderer),
mLinkedInParallel(false)
{ {
ASSERT(mFunctions); ASSERT(mFunctions);
ASSERT(mStateManager); ASSERT(mStateManager);
...@@ -125,18 +130,54 @@ void ProgramGL::setSeparable(bool separable) ...@@ -125,18 +130,54 @@ void ProgramGL::setSeparable(bool separable)
mFunctions->programParameteri(mProgramID, GL_PROGRAM_SEPARABLE, separable ? GL_TRUE : GL_FALSE); 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, std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog) 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(); preLink();
if (mState.getAttachedShader(gl::ShaderType::Compute)) if (mState.getAttachedShader(gl::ShaderType::Compute))
...@@ -145,12 +186,6 @@ angle::Result ProgramGL::linkImpl(const gl::Context *context, ...@@ -145,12 +186,6 @@ angle::Result ProgramGL::linkImpl(const gl::Context *context,
GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute)); GetImplAs<ShaderGL>(mState.getAttachedShader(gl::ShaderType::Compute));
mFunctions->attachShader(mProgramID, computeShaderGL->getShaderID()); mFunctions->attachShader(mProgramID, computeShaderGL->getShaderID());
// Link and verify
mFunctions->linkProgram(mProgramID);
// Detach the shaders
mFunctions->detachShader(mProgramID, computeShaderGL->getShaderID());
} }
else else
{ {
...@@ -321,34 +356,85 @@ angle::Result ProgramGL::linkImpl(const gl::Context *context, ...@@ -321,34 +356,85 @@ angle::Result ProgramGL::linkImpl(const gl::Context *context,
} }
} }
} }
}
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); mFunctions->linkProgram(mProgramID);
// Detach the shaders // Make sure the driver actually does the link job.
mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID()); GLint linkStatus = GL_FALSE;
mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID()); mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
if (geometryShaderGL)
return false;
});
auto postLinkImplTask = [this, &infoLog, &resources](bool fallbackToMainContext) {
if (fallbackToMainContext)
{ {
mFunctions->detachShader(mProgramID, geometryShaderGL->getShaderID()); mFunctions->linkProgram(mProgramID);
} }
}
// Verify the link if (mState.getAttachedShader(gl::ShaderType::Compute))
if (!checkLinkStatus(infoLog)) {
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);
} }
else
if (mWorkarounds.alwaysCallUseProgramAfterLink)
{ {
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*/) GLboolean ProgramGL::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/)
......
...@@ -19,6 +19,7 @@ namespace rx ...@@ -19,6 +19,7 @@ namespace rx
{ {
class FunctionsGL; class FunctionsGL;
class RendererGL;
class StateManagerGL; class StateManagerGL;
class ProgramGL : public ProgramImpl class ProgramGL : public ProgramImpl
...@@ -28,7 +29,8 @@ class ProgramGL : public ProgramImpl ...@@ -28,7 +29,8 @@ class ProgramGL : public ProgramImpl
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
StateManagerGL *stateManager, StateManagerGL *stateManager,
bool enablePathRendering); bool enablePathRendering,
const std::shared_ptr<RendererGL> &renderer);
~ProgramGL() override; ~ProgramGL() override;
angle::Result load(const gl::Context *context, angle::Result load(const gl::Context *context,
...@@ -114,12 +116,12 @@ class ProgramGL : public ProgramImpl ...@@ -114,12 +116,12 @@ class ProgramGL : public ProgramImpl
const gl::Program::DirtyBits &dirtyBits) override; const gl::Program::DirtyBits &dirtyBits) override;
private: private:
class LinkTask;
class LinkEventGL;
void preLink(); void preLink();
bool checkLinkStatus(gl::InfoLog &infoLog); bool checkLinkStatus(gl::InfoLog &infoLog);
void postLink(); void postLink();
angle::Result linkImpl(const gl::Context *contextImpl,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog);
void reapplyUBOBindingsIfNeeded(const gl::Context *context); void reapplyUBOBindingsIfNeeded(const gl::Context *context);
...@@ -161,6 +163,10 @@ class ProgramGL : public ProgramImpl ...@@ -161,6 +163,10 @@ class ProgramGL : public ProgramImpl
GLint mMultiviewBaseViewLayerIndexUniformLocation; GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID; GLuint mProgramID;
std::shared_ptr<RendererGL> mRenderer;
bool mLinkedInParallel;
}; };
} // namespace rx } // namespace rx
......
...@@ -222,6 +222,11 @@ RendererGL::~RendererGL() ...@@ -222,6 +222,11 @@ RendererGL::~RendererGL()
SafeDelete(mBlitter); SafeDelete(mBlitter);
SafeDelete(mMultiviewClearer); SafeDelete(mMultiviewClearer);
SafeDelete(mStateManager); SafeDelete(mStateManager);
std::lock_guard<std::mutex> lock(mWorkerMutex);
ASSERT(mCurrentWorkerContexts.empty());
mWorkerContextPool.clear();
} }
angle::Result RendererGL::flush() angle::Result RendererGL::flush()
...@@ -559,4 +564,71 @@ angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers) ...@@ -559,4 +564,71 @@ angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers)
return angle::Result::Continue; 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 } // namespace rx
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#ifndef LIBANGLE_RENDERER_GL_RENDERERGL_H_ #ifndef LIBANGLE_RENDERER_GL_RENDERERGL_H_
#define LIBANGLE_RENDERER_GL_RENDERERGL_H_ #define LIBANGLE_RENDERER_GL_RENDERERGL_H_
#include <list>
#include <mutex>
#include <thread>
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/Version.h" #include "libANGLE/Version.h"
...@@ -39,8 +43,33 @@ class BlitGL; ...@@ -39,8 +43,33 @@ class BlitGL;
class ClearMultiviewGL; class ClearMultiviewGL;
class ContextImpl; class ContextImpl;
class FunctionsGL; class FunctionsGL;
class RendererGL;
class StateManagerGL; 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 class RendererGL : angle::NonCopyable
{ {
public: public:
...@@ -149,6 +178,14 @@ class RendererGL : angle::NonCopyable ...@@ -149,6 +178,14 @@ class RendererGL : angle::NonCopyable
angle::Result memoryBarrier(GLbitfield barriers); angle::Result memoryBarrier(GLbitfield barriers);
angle::Result memoryBarrierByRegion(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: private:
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
...@@ -174,6 +211,13 @@ class RendererGL : angle::NonCopyable ...@@ -174,6 +211,13 @@ class RendererGL : angle::NonCopyable
mutable gl::Extensions mNativeExtensions; mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations; mutable gl::Limitations mNativeLimitations;
mutable MultiviewImplementationTypeGL mMultiviewImplementationType; 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 } // namespace rx
......
...@@ -23,11 +23,13 @@ namespace rx ...@@ -23,11 +23,13 @@ namespace rx
ShaderGL::ShaderGL(const gl::ShaderState &data, ShaderGL::ShaderGL(const gl::ShaderState &data,
GLuint shaderID, GLuint shaderID,
MultiviewImplementationTypeGL multiviewImplementationType, MultiviewImplementationTypeGL multiviewImplementationType,
const FunctionsGL *functions) const std::shared_ptr<RendererGL> &renderer)
: ShaderImpl(data), : ShaderImpl(data),
mShaderID(shaderID), mShaderID(shaderID),
mMultiviewImplementationType(multiviewImplementationType), mMultiviewImplementationType(multiviewImplementationType),
mFunctions(functions) mRenderer(renderer),
mFallbackToMainThread(true),
mCompileStatus(GL_FALSE)
{} {}
ShaderGL::~ShaderGL() ShaderGL::~ShaderGL()
...@@ -37,7 +39,7 @@ ShaderGL::~ShaderGL() ...@@ -37,7 +39,7 @@ ShaderGL::~ShaderGL()
void ShaderGL::destroy() void ShaderGL::destroy()
{ {
mFunctions->deleteShader(mShaderID); mRenderer->getFunctions()->deleteShader(mShaderID);
mShaderID = 0; mShaderID = 0;
} }
...@@ -138,41 +140,70 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(const gl::Context *cont ...@@ -138,41 +140,70 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(const gl::Context *cont
options |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER; options |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
} }
mFallbackToMainThread = true;
return options; return options;
} }
bool ShaderGL::postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) void ShaderGL::compileAndCheckShader(const char *source)
{ {
// Translate the ESSL into GLSL const FunctionsGL *functions = mRenderer->getFunctions();
const char *translatedSourceCString = mData.getTranslatedSource().c_str(); functions->shaderSource(mShaderID, 1, &source, nullptr);
functions->compileShader(mShaderID);
// Set the source
mFunctions->shaderSource(mShaderID, 1, &translatedSourceCString, nullptr);
mFunctions->compileShader(mShaderID);
// Check for compile errors from the native driver // Check for compile errors from the native driver
GLint compileStatus = GL_FALSE; mCompileStatus = GL_FALSE;
mFunctions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &compileStatus); functions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &mCompileStatus);
if (compileStatus == GL_FALSE) if (mCompileStatus == GL_FALSE)
{ {
// Compilation failed, put the error into the info log // Compilation failed, put the error into the info log
GLint infoLogLength = 0; 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 // Info log length includes the null terminator, so 1 means that the info log is an empty
// string. // string.
if (infoLogLength > 1) if (infoLogLength > 1)
{ {
std::vector<char> buf(infoLogLength); std::vector<char> buf(infoLogLength);
mFunctions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]); functions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]);
*infoLog = &buf[0]; mInfoLog = &buf[0];
WARN() << std::endl << *infoLog; WARN() << std::endl << mInfoLog;
} }
else else
{ {
WARN() << std::endl << "Shader compilation failed with no info log."; 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; return false;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
namespace rx namespace rx
{ {
class FunctionsGL; class RendererGL;
struct WorkaroundsGL; struct WorkaroundsGL;
enum class MultiviewImplementationTypeGL; enum class MultiviewImplementationTypeGL;
...@@ -23,7 +23,7 @@ class ShaderGL : public ShaderImpl ...@@ -23,7 +23,7 @@ class ShaderGL : public ShaderImpl
ShaderGL(const gl::ShaderState &data, ShaderGL(const gl::ShaderState &data,
GLuint shaderID, GLuint shaderID,
MultiviewImplementationTypeGL multiviewImplementationType, MultiviewImplementationTypeGL multiviewImplementationType,
const FunctionsGL *functions); const std::shared_ptr<RendererGL> &renderer);
~ShaderGL() override; ~ShaderGL() override;
void destroy() override; void destroy() override;
...@@ -32,15 +32,21 @@ class ShaderGL : public ShaderImpl ...@@ -32,15 +32,21 @@ class ShaderGL : public ShaderImpl
ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context, ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context,
std::stringstream *sourceStream, std::stringstream *sourceStream,
std::string *sourcePath) override; std::string *sourcePath) override;
void compileAsync(const std::string &source) override;
bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override; bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override;
std::string getDebugInfo() const override; std::string getDebugInfo() const override;
GLuint getShaderID() const; GLuint getShaderID() const;
private: private:
void compileAndCheckShader(const char *source);
GLuint mShaderID; GLuint mShaderID;
MultiviewImplementationTypeGL mMultiviewImplementationType; MultiviewImplementationTypeGL mMultiviewImplementationType;
const FunctionsGL *mFunctions; std::shared_ptr<RendererGL> mRenderer;
bool mFallbackToMainThread;
GLint mCompileStatus;
std::string mInfoLog;
}; };
} // namespace rx } // namespace rx
......
...@@ -167,6 +167,11 @@ struct WorkaroundsGL ...@@ -167,6 +167,11 @@ struct WorkaroundsGL
// Older Qualcomm drivers generate errors when querying the number of bits in timer queries, ex: // 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 // GetQueryivEXT(GL_TIME_ELAPSED, GL_QUERY_COUNTER_BITS). http://anglebug.com/3027
bool queryCounterBitsGeneratesErrors = false; 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; inline WorkaroundsGL::WorkaroundsGL() = default;
......
...@@ -14,9 +14,14 @@ ...@@ -14,9 +14,14 @@
struct _CGLContextObject; struct _CGLContextObject;
typedef _CGLContextObject *CGLContextObj; typedef _CGLContextObject *CGLContextObj;
struct _CGLPixelFormatObject;
typedef _CGLPixelFormatObject *CGLPixelFormatObj;
namespace rx namespace rx
{ {
class WorkerContext;
class DisplayCGL : public DisplayGL class DisplayCGL : public DisplayGL
{ {
public: public:
...@@ -67,6 +72,8 @@ class DisplayCGL : public DisplayGL ...@@ -67,6 +72,8 @@ class DisplayCGL : public DisplayGL
CGLContextObj getCGLContext() const; CGLContextObj getCGLContext() const;
WorkerContext *createWorkerContext(std::string *infoLog);
private: private:
egl::Error makeCurrentSurfaceless(gl::Context *context) override; egl::Error makeCurrentSurfaceless(gl::Context *context) override;
...@@ -77,6 +84,7 @@ class DisplayCGL : public DisplayGL ...@@ -77,6 +84,7 @@ class DisplayCGL : public DisplayGL
egl::Display *mEGLDisplay; egl::Display *mEGLDisplay;
CGLContextObj mContext; CGLContextObj mContext;
CGLPixelFormatObj mPixelFormat;
}; };
} // namespace rx } // namespace rx
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/renderer/gl/ContextGL.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/IOSurfaceSurfaceCGL.h"
#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h" #include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
#include "libANGLE/renderer/gl/cgl/RendererCGL.h"
#include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h" #include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
namespace namespace
...@@ -49,7 +49,7 @@ class FunctionsGLCGL : public FunctionsGL ...@@ -49,7 +49,7 @@ class FunctionsGLCGL : public FunctionsGL
}; };
DisplayCGL::DisplayCGL(const egl::DisplayState &state) DisplayCGL::DisplayCGL(const egl::DisplayState &state)
: DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr) : DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr), mPixelFormat(nullptr)
{} {}
DisplayCGL::~DisplayCGL() {} DisplayCGL::~DisplayCGL() {}
...@@ -58,22 +58,21 @@ egl::Error DisplayCGL::initialize(egl::Display *display) ...@@ -58,22 +58,21 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
{ {
mEGLDisplay = display; mEGLDisplay = display;
CGLPixelFormatObj pixelFormat;
{ {
// TODO(cwallez) investigate which pixel format we want // TODO(cwallez) investigate which pixel format we want
CGLPixelFormatAttribute attribs[] = { CGLPixelFormatAttribute attribs[] = {
kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core), kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
static_cast<CGLPixelFormatAttribute>(0)}; static_cast<CGLPixelFormatAttribute>(0)};
GLint nVirtualScreens = 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."; return egl::EglNotInitialized() << "Could not create the context's pixel format.";
} }
} }
CGLCreateContext(pixelFormat, nullptr, &mContext); CGLCreateContext(mPixelFormat, nullptr, &mContext);
if (mContext == nullptr) if (mContext == nullptr)
{ {
return egl::EglNotInitialized() << "Could not create the CGL context."; return egl::EglNotInitialized() << "Could not create the CGL context.";
...@@ -94,7 +93,7 @@ egl::Error DisplayCGL::initialize(egl::Display *display) ...@@ -94,7 +93,7 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLCGL(handle)); std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLCGL(handle));
functionsGL->initialize(display->getAttributeMap()); 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(); const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0)) if (maxVersion < gl::Version(2, 0))
...@@ -316,4 +315,55 @@ egl::Error DisplayCGL::makeCurrentSurfaceless(gl::Context *context) ...@@ -316,4 +315,55 @@ egl::Error DisplayCGL::makeCurrentSurfaceless(gl::Context *context)
// default. // default.
return egl::NoError(); 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);
}
} }
//
// 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_
//
// 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
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "libANGLE/renderer/gl/egl/DisplayEGL.h" #include "libANGLE/renderer/gl/egl/DisplayEGL.h"
#include "libANGLE/renderer/gl/egl/ImageEGL.h" #include "libANGLE/renderer/gl/egl/ImageEGL.h"
#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx namespace rx
{ {
...@@ -39,7 +38,8 @@ std::string DisplayEGL::getVendorString() const ...@@ -39,7 +38,8 @@ std::string DisplayEGL::getVendorString() const
egl::Error DisplayEGL::initializeContext(EGLContext shareContext, egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes, const egl::AttributeMap &eglAttributes,
EGLContext *outContext) const EGLContext *outContext,
native_egl::AttributeVector *outAttribs) const
{ {
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion); gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
...@@ -97,6 +97,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -97,6 +97,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
if (context != EGL_NO_CONTEXT) if (context != EGL_NO_CONTEXT)
{ {
*outContext = context; *outContext = context;
*outAttribs = attribList;
return egl::NoError(); return egl::NoError();
} }
} }
......
...@@ -11,10 +11,13 @@ ...@@ -11,10 +11,13 @@
#include "libANGLE/renderer/gl/DisplayGL.h" #include "libANGLE/renderer/gl/DisplayGL.h"
#include "libANGLE/renderer/gl/egl/FunctionsEGL.h" #include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx namespace rx
{ {
class WorkerContext;
class DisplayEGL : public DisplayGL class DisplayEGL : public DisplayGL
{ {
public: public:
...@@ -32,10 +35,15 @@ class DisplayEGL : public DisplayGL ...@@ -32,10 +35,15 @@ class DisplayEGL : public DisplayGL
virtual void destroyNativeContext(EGLContext context) = 0; virtual void destroyNativeContext(EGLContext context) = 0;
virtual WorkerContext *createWorkerContext(std::string *infoLog,
EGLContext sharedContext,
const native_egl::AttributeVector workerAttribs) = 0;
protected: protected:
egl::Error initializeContext(EGLContext shareContext, egl::Error initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes, const egl::AttributeMap &eglAttributes,
EGLContext *outContext) const; EGLContext *outContext,
native_egl::AttributeVector *outAttribs) const;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
......
...@@ -14,8 +14,12 @@ namespace rx ...@@ -14,8 +14,12 @@ namespace rx
RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL, RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayEGL *display, DisplayEGL *display,
EGLContext context) EGLContext context,
: RendererGL(std::move(functionsGL), attribMap), mDisplay(display), mContext(context) const native_egl::AttributeVector attribs)
: RendererGL(std::move(functionsGL), attribMap),
mDisplay(display),
mContext(context),
mAttribs(attribs)
{} {}
RendererEGL::~RendererEGL() RendererEGL::~RendererEGL()
...@@ -29,4 +33,9 @@ EGLContext RendererEGL::getContext() const ...@@ -29,4 +33,9 @@ EGLContext RendererEGL::getContext() const
return mContext; return mContext;
} }
WorkerContext *RendererEGL::createWorkerContext(std::string *infoLog)
{
return mDisplay->createWorkerContext(infoLog, mContext, mAttribs);
}
} // namespace rx } // namespace rx
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_ #define LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
#include "libANGLE/renderer/gl/RendererGL.h" #include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/egl/egl_utils.h"
namespace rx namespace rx
{ {
...@@ -21,14 +22,18 @@ class RendererEGL : public RendererGL ...@@ -21,14 +22,18 @@ class RendererEGL : public RendererGL
RendererEGL(std::unique_ptr<FunctionsGL> functionsGL, RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayEGL *display, DisplayEGL *display,
EGLContext context); EGLContext context,
const native_egl::AttributeVector attribs);
~RendererEGL() override; ~RendererEGL() override;
EGLContext getContext() const; EGLContext getContext() const;
WorkerContext *createWorkerContext(std::string *infoLog) override;
private: private:
DisplayEGL *mDisplay; DisplayEGL *mDisplay;
EGLContext mContext; EGLContext mContext;
const native_egl::AttributeVector mAttribs;
}; };
} // namespace rx } // namespace rx
......
...@@ -602,7 +602,8 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext, ...@@ -602,7 +602,8 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
std::shared_ptr<RendererEGL> *outRenderer) std::shared_ptr<RendererEGL> *outRenderer)
{ {
EGLContext context = EGL_NO_CONTEXT; 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) if (mEGL->makeCurrent(mDummyPbuffer, context) == EGL_FALSE)
{ {
...@@ -613,7 +614,8 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext, ...@@ -613,7 +614,8 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL()); std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(mDisplayAttributes); 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 &currentContext = mCurrentNativeContext[std::this_thread::get_id()]; CurrentNativeContext &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
if (makeNewContextCurrent) if (makeNewContextCurrent)
...@@ -634,4 +636,58 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext, ...@@ -634,4 +636,58 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
return egl::NoError(); 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 } // namespace rx
...@@ -78,6 +78,10 @@ class DisplayAndroid : public DisplayEGL ...@@ -78,6 +78,10 @@ class DisplayAndroid : public DisplayEGL
void destroyNativeContext(EGLContext context) override; void destroyNativeContext(EGLContext context) override;
WorkerContext *createWorkerContext(std::string *infoLog,
EGLContext sharedContext,
const native_egl::AttributeVector workerAttribs) override;
private: private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
......
...@@ -524,7 +524,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display) ...@@ -524,7 +524,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
} }
EGLContext context = EGL_NO_CONTEXT; 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)) if (!mEGL->makeCurrent(EGL_NO_SURFACE, context))
{ {
...@@ -534,8 +535,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display) ...@@ -534,8 +535,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL()); std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(display->getAttributeMap()); functionsGL->initialize(display->getAttributeMap());
mRenderer.reset( mRenderer.reset(new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this,
new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this, context)); context, attribs));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion(); const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0)) if (maxVersion < gl::Version(2, 0))
{ {
...@@ -1021,4 +1022,55 @@ egl::Error DisplayOzone::makeCurrentSurfaceless(gl::Context *context) ...@@ -1021,4 +1022,55 @@ egl::Error DisplayOzone::makeCurrentSurfaceless(gl::Context *context)
return egl::NoError(); 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 } // namespace rx
...@@ -156,6 +156,10 @@ class DisplayOzone final : public DisplayEGL ...@@ -156,6 +156,10 @@ class DisplayOzone final : public DisplayEGL
// one required so that the subsequent swapBuffers acts as expected. // one required so that the subsequent swapBuffers acts as expected.
void setSwapInterval(EGLSurface drawable, SwapControlData *data); void setSwapInterval(EGLSurface drawable, SwapControlData *data);
WorkerContext *createWorkerContext(std::string *infoLog,
EGLContext sharedContext,
const native_egl::AttributeVector workerAttribs) override;
private: private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/ContextGL.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/PbufferSurfaceGLX.h"
#include "libANGLE/renderer/gl/glx/RendererGLX.h"
#include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h" #include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h"
#include "libANGLE/renderer/gl/renderergl_utils.h" #include "libANGLE/renderer/gl/renderergl_utils.h"
...@@ -56,7 +56,9 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state) ...@@ -56,7 +56,9 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state)
: DisplayGL(state), : DisplayGL(state),
mRequestedVisual(-1), mRequestedVisual(-1),
mContextConfig(nullptr), mContextConfig(nullptr),
mVisuals(nullptr),
mContext(nullptr), mContext(nullptr),
mSharedContext(nullptr),
mDummyPbuffer(0), mDummyPbuffer(0),
mUsesNewXDisplay(false), mUsesNewXDisplay(false),
mIsMesa(false), mIsMesa(false),
...@@ -228,21 +230,21 @@ egl::Error DisplayGLX::initialize(egl::Display *display) ...@@ -228,21 +230,21 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
visualTemplate.visualid = getGLXFBConfigAttrib(mContextConfig, GLX_VISUAL_ID); visualTemplate.visualid = getGLXFBConfigAttrib(mContextConfig, GLX_VISUAL_ID);
int numVisuals = 0; int numVisuals = 0;
XVisualInfo *visuals = mVisuals = XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals);
XGetVisualInfo(mXDisplay, VisualIDMask, &visualTemplate, &numVisuals);
if (numVisuals <= 0) if (numVisuals <= 0)
{ {
return egl::EglNotInitialized() << "Could not get the visual info from the fb config"; return egl::EglNotInitialized() << "Could not get the visual info from the fb config";
} }
ASSERT(numVisuals == 1); ASSERT(numVisuals == 1);
mContext = mGLX.createContext(&visuals[0], nullptr, true); mContext = mGLX.createContext(&mVisuals[0], nullptr, true);
XFree(visuals);
if (!mContext) if (!mContext)
{ {
return egl::EglNotInitialized() << "Could not create GL context."; return egl::EglNotInitialized() << "Could not create GL context.";
} }
mSharedContext = mGLX.createContext(&mVisuals[0], mContext, True);
} }
ASSERT(mContext); ASSERT(mContext);
...@@ -285,9 +287,22 @@ egl::Error DisplayGLX::initialize(egl::Display *display) ...@@ -285,9 +287,22 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
return egl::EglNotInitialized() << "Intel or NVIDIA OpenGL ES drivers are not supported."; 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(); syncXCommands();
mRenderer.reset(new RendererGL(std::move(functionsGL), eglAttributes)); mRenderer.reset(new RendererGLX(std::move(functionsGL), eglAttributes, this));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion(); const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0)) if (maxVersion < gl::Version(2, 0))
{ {
...@@ -301,18 +316,36 @@ void DisplayGLX::terminate() ...@@ -301,18 +316,36 @@ void DisplayGLX::terminate()
{ {
DisplayGL::terminate(); DisplayGL::terminate();
if (mVisuals)
{
XFree(mVisuals);
mVisuals = 0;
}
if (mDummyPbuffer) if (mDummyPbuffer)
{ {
mGLX.destroyPbuffer(mDummyPbuffer); mGLX.destroyPbuffer(mDummyPbuffer);
mDummyPbuffer = 0; mDummyPbuffer = 0;
} }
for (auto &workerPbuffer : mWorkerPbufferPool)
{
mGLX.destroyPbuffer(workerPbuffer);
}
mWorkerPbufferPool.clear();
if (mContext) if (mContext)
{ {
mGLX.destroyContext(mContext); mGLX.destroyContext(mContext);
mContext = nullptr; mContext = nullptr;
} }
if (mSharedContext)
{
mGLX.destroyContext(mSharedContext);
mSharedContext = nullptr;
}
mGLX.terminate(); mGLX.terminate();
mRenderer.reset(); mRenderer.reset();
...@@ -811,34 +844,34 @@ int DisplayGLX::getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const ...@@ -811,34 +844,34 @@ int DisplayGLX::getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const
egl::Error DisplayGLX::createContextAttribs(glx::FBConfig, egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
const Optional<gl::Version> &version, const Optional<gl::Version> &version,
int profileMask, int profileMask,
glx::Context *context) const glx::Context *context)
{ {
std::vector<int> attribs; mAttribs.clear();
if (mHasARBCreateContextRobustness) if (mHasARBCreateContextRobustness)
{ {
attribs.push_back(GLX_CONTEXT_FLAGS_ARB); mAttribs.push_back(GLX_CONTEXT_FLAGS_ARB);
attribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB); mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); mAttribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
} }
if (version.valid()) if (version.valid())
{ {
attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); mAttribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
attribs.push_back(version.value().major); mAttribs.push_back(version.value().major);
attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); mAttribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
attribs.push_back(version.value().minor); mAttribs.push_back(version.value().minor);
} }
if (profileMask != 0 && mHasARBCreateContextProfile) if (profileMask != 0 && mHasARBCreateContextProfile)
{ {
attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); mAttribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
attribs.push_back(profileMask); mAttribs.push_back(profileMask);
} }
attribs.push_back(None); mAttribs.push_back(None);
// When creating a context with glXCreateContextAttribsARB, a variety of X11 errors can // 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 // be generated. To prevent these errors from crashing our process, we simply ignore
...@@ -847,14 +880,95 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig, ...@@ -847,14 +880,95 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
// (the error handler is NOT per-display). // (the error handler is NOT per-display).
XSync(mXDisplay, False); XSync(mXDisplay, False);
auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors); auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
*context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, attribs.data()); *context = mGLX.createContextAttribsARB(mContextConfig, nullptr, True, mAttribs.data());
XSetErrorHandler(oldErrorHandler); XSetErrorHandler(oldErrorHandler);
if (!*context) if (!*context)
{ {
return egl::EglNotInitialized() << "Could not create GL context."; return egl::EglNotInitialized() << "Could not create GL context.";
} }
mSharedContext = mGLX.createContextAttribsARB(mContextConfig, mContext, True, mAttribs.data());
return egl::NoError(); 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 } // namespace rx
...@@ -20,6 +20,7 @@ namespace rx ...@@ -20,6 +20,7 @@ namespace rx
{ {
class FunctionsGLX; class FunctionsGLX;
class WorkerContext;
// State-tracking data for the swap control to allow DisplayGLX to remember per // State-tracking data for the swap control to allow DisplayGLX to remember per
// drawable information for swap control. // drawable information for swap control.
...@@ -97,6 +98,8 @@ class DisplayGLX : public DisplayGL ...@@ -97,6 +98,8 @@ class DisplayGLX : public DisplayGL
bool isValidWindowVisualId(unsigned long visualId) const; bool isValidWindowVisualId(unsigned long visualId) const;
WorkerContext *createWorkerContext(std::string *infoLog);
private: private:
egl::Error initializeContext(glx::FBConfig config, egl::Error initializeContext(glx::FBConfig config,
const egl::AttributeMap &eglAttributes, const egl::AttributeMap &eglAttributes,
...@@ -111,7 +114,7 @@ class DisplayGLX : public DisplayGL ...@@ -111,7 +114,7 @@ class DisplayGLX : public DisplayGL
egl::Error createContextAttribs(glx::FBConfig, egl::Error createContextAttribs(glx::FBConfig,
const Optional<gl::Version> &version, const Optional<gl::Version> &version,
int profileMask, int profileMask,
glx::Context *context) const; glx::Context *context);
std::shared_ptr<RendererGL> mRenderer; std::shared_ptr<RendererGL> mRenderer;
...@@ -119,10 +122,15 @@ class DisplayGLX : public DisplayGL ...@@ -119,10 +122,15 @@ class DisplayGLX : public DisplayGL
EGLint mRequestedVisual; EGLint mRequestedVisual;
glx::FBConfig mContextConfig; glx::FBConfig mContextConfig;
std::vector<int> mAttribs;
XVisualInfo *mVisuals;
glx::Context mContext; glx::Context mContext;
glx::Context mSharedContext;
// A pbuffer the context is current on during ANGLE initialization // A pbuffer the context is current on during ANGLE initialization
glx::Pbuffer mDummyPbuffer; glx::Pbuffer mDummyPbuffer;
std::vector<glx::Pbuffer> mWorkerPbufferPool;
bool mUsesNewXDisplay; bool mUsesNewXDisplay;
bool mIsMesa; bool mIsMesa;
bool mHasMultisample; bool mHasMultisample;
......
//
// 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
//
// 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_
...@@ -1442,6 +1442,8 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround ...@@ -1442,6 +1442,8 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
workarounds->unsizedsRGBReadPixelsDoesntTransform = IsAndroid() && IsQualcomm(vendor); workarounds->unsizedsRGBReadPixelsDoesntTransform = IsAndroid() && IsQualcomm(vendor);
workarounds->queryCounterBitsGeneratesErrors = IsNexus5X(vendor, device); workarounds->queryCounterBitsGeneratesErrors = IsNexus5X(vendor, device);
workarounds->dontRelinkProgramsInParallel = IsAndroid() || (IsWindows() && IsIntel(vendor));
} }
void ApplyWorkarounds(const FunctionsGL *functions, gl::Workarounds *workarounds) void ApplyWorkarounds(const FunctionsGL *functions, gl::Workarounds *workarounds)
......
...@@ -9,18 +9,19 @@ ...@@ -9,18 +9,19 @@
#ifndef LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_ #ifndef LIBANGLE_RENDERER_GL_WGL_DISPLAYWGL_H_
#define 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 "libANGLE/renderer/gl/DisplayGL.h"
#include <GL/wglext.h> #include <GL/wglext.h>
#include <thread>
#include <unordered_map>
namespace rx namespace rx
{ {
class FunctionsWGL; class FunctionsWGL;
class RendererWGL; class RendererWGL;
class WorkerContext;
class DisplayWGL : public DisplayGL class DisplayWGL : public DisplayGL
{ {
...@@ -80,6 +81,10 @@ class DisplayWGL : public DisplayGL ...@@ -80,6 +81,10 @@ class DisplayWGL : public DisplayGL
void destroyNativeContext(HGLRC context); void destroyNativeContext(HGLRC context);
WorkerContext *createWorkerContext(std::string *infoLog,
HGLRC sharedContext,
const std::vector<int> &workerContextAttribs);
private: private:
egl::Error initializeImpl(egl::Display *display); egl::Error initializeImpl(egl::Display *display);
void destroy(); void destroy();
...@@ -91,8 +96,15 @@ class DisplayWGL : public DisplayGL ...@@ -91,8 +96,15 @@ class DisplayWGL : public DisplayGL
egl::Error makeCurrentSurfaceless(gl::Context *context) override; egl::Error makeCurrentSurfaceless(gl::Context *context) override;
HGLRC initializeContextAttribs(const egl::AttributeMap &eglAttributes) const; HGLRC initializeContextAttribs(const egl::AttributeMap &eglAttributes,
HGLRC createContextAttribs(const gl::Version &version, int profileMask) const; 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); egl::Error createRenderer(std::shared_ptr<RendererWGL> *outRenderer);
...@@ -132,6 +144,9 @@ class DisplayWGL : public DisplayGL ...@@ -132,6 +144,9 @@ class DisplayWGL : public DisplayGL
size_t refCount; size_t refCount;
}; };
std::map<IUnknown *, D3DObjectHandle> mRegisteredD3DDevices; std::map<IUnknown *, D3DObjectHandle> mRegisteredD3DDevices;
bool mHasWorkerContexts;
bool mUseARBShare;
}; };
} // namespace rx } // namespace rx
......
...@@ -14,12 +14,22 @@ namespace rx ...@@ -14,12 +14,22 @@ namespace rx
RendererWGL::RendererWGL(std::unique_ptr<FunctionsGL> functionsGL, RendererWGL::RendererWGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayWGL *display, DisplayWGL *display,
HGLRC context) HGLRC context,
: RendererGL(std::move(functionsGL), attribMap), mDisplay(display), mContext(context) HGLRC sharedContext,
const std::vector<int> workerContextAttribs)
: RendererGL(std::move(functionsGL), attribMap),
mDisplay(display),
mContext(context),
mSharedContext(sharedContext),
mWorkerContextAttribs(workerContextAttribs)
{} {}
RendererWGL::~RendererWGL() RendererWGL::~RendererWGL()
{ {
if (mSharedContext != nullptr)
{
mDisplay->destroyNativeContext(mSharedContext);
}
mDisplay->destroyNativeContext(mContext); mDisplay->destroyNativeContext(mContext);
mContext = nullptr; mContext = nullptr;
} }
...@@ -29,4 +39,9 @@ HGLRC RendererWGL::getContext() const ...@@ -29,4 +39,9 @@ HGLRC RendererWGL::getContext() const
return mContext; return mContext;
} }
WorkerContext *RendererWGL::createWorkerContext(std::string *infoLog)
{
return mDisplay->createWorkerContext(infoLog, mSharedContext, mWorkerContextAttribs);
}
} // namespace rx } // namespace rx
...@@ -22,14 +22,19 @@ class RendererWGL : public RendererGL ...@@ -22,14 +22,19 @@ class RendererWGL : public RendererGL
RendererWGL(std::unique_ptr<FunctionsGL> functionsGL, RendererWGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayWGL *display, DisplayWGL *display,
HGLRC context); HGLRC context,
HGLRC sharedContext,
const std::vector<int> workerContextAttribs);
~RendererWGL() override; ~RendererWGL() override;
HGLRC getContext() const; HGLRC getContext() const;
private: private:
WorkerContext *createWorkerContext(std::string *infoLog) override;
DisplayWGL *mDisplay; DisplayWGL *mDisplay;
HGLRC mContext; HGLRC mContext;
HGLRC mSharedContext;
const std::vector<int> mWorkerContextAttribs;
}; };
} // namespace rx } // namespace rx
......
...@@ -673,6 +673,8 @@ libangle_gl_glx_sources = [ ...@@ -673,6 +673,8 @@ libangle_gl_glx_sources = [
"src/libANGLE/renderer/gl/glx/DisplayGLX.h", "src/libANGLE/renderer/gl/glx/DisplayGLX.h",
"src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp", "src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp",
"src/libANGLE/renderer/gl/glx/FunctionsGLX.h", "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.cpp",
"src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h", "src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h",
"src/libANGLE/renderer/gl/glx/SurfaceGLX.h", "src/libANGLE/renderer/gl/glx/SurfaceGLX.h",
...@@ -730,6 +732,8 @@ libangle_gl_cgl_sources = [ ...@@ -730,6 +732,8 @@ libangle_gl_cgl_sources = [
"src/libANGLE/renderer/gl/cgl/DisplayCGL.h", "src/libANGLE/renderer/gl/cgl/DisplayCGL.h",
"src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.mm", "src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.mm",
"src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h", "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.mm",
"src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h", "src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h",
"src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm", "src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm",
......
...@@ -1912,7 +1912,9 @@ TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2) ...@@ -1912,7 +1912,9 @@ TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2)
TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters) TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters)
{ {
std::stringstream vertexShaderStream; 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" vertexShaderStream << "#version 300 es\n"
"precision highp float;\n" "precision highp float;\n"
......
...@@ -19,7 +19,7 @@ using namespace angle; ...@@ -19,7 +19,7 @@ using namespace angle;
namespace namespace
{ {
enum class LinkProgramOption enum class TaskOption
{ {
CompileOnly, CompileOnly,
CompileAndLink, CompileAndLink,
...@@ -27,9 +27,17 @@ enum class LinkProgramOption ...@@ -27,9 +27,17 @@ enum class LinkProgramOption
Unspecified Unspecified
}; };
enum class ThreadOption
{
SingleThread,
MultiThread,
Unspecified
};
struct LinkProgramParams final : public RenderTestParams struct LinkProgramParams final : public RenderTestParams
{ {
LinkProgramParams(LinkProgramOption optionIn) LinkProgramParams(TaskOption taskOptionIn, ThreadOption threadOptionIn)
{ {
iterationsPerStep = 1; iterationsPerStep = 1;
...@@ -37,7 +45,8 @@ struct LinkProgramParams final : public RenderTestParams ...@@ -37,7 +45,8 @@ struct LinkProgramParams final : public RenderTestParams
minorVersion = 0; minorVersion = 0;
windowWidth = 256; windowWidth = 256;
windowHeight = 256; windowHeight = 256;
option = optionIn; taskOption = taskOptionIn;
threadOption = threadOptionIn;
} }
std::string suffix() const override std::string suffix() const override
...@@ -45,10 +54,23 @@ struct LinkProgramParams final : public RenderTestParams ...@@ -45,10 +54,23 @@ struct LinkProgramParams final : public RenderTestParams
std::stringstream strstr; std::stringstream strstr;
strstr << RenderTestParams::suffix(); strstr << RenderTestParams::suffix();
if (option == LinkProgramOption::CompileOnly) if (taskOption == TaskOption::CompileOnly)
{ {
strstr << "_compile_only"; 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) if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
{ {
...@@ -58,7 +80,8 @@ struct LinkProgramParams final : public RenderTestParams ...@@ -58,7 +80,8 @@ struct LinkProgramParams final : public RenderTestParams
return strstr.str(); return strstr.str();
} }
LinkProgramOption option; TaskOption taskOption;
ThreadOption threadOption;
}; };
std::ostream &operator<<(std::ostream &os, const LinkProgramParams &params) std::ostream &operator<<(std::ostream &os, const LinkProgramParams &params)
...@@ -85,6 +108,11 @@ LinkProgramBenchmark::LinkProgramBenchmark() : ANGLERenderTest("LinkProgram", Ge ...@@ -85,6 +108,11 @@ LinkProgramBenchmark::LinkProgramBenchmark() : ANGLERenderTest("LinkProgram", Ge
void LinkProgramBenchmark::initializeBenchmark() 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), 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),
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 @@ void LinkProgramBenchmark::drawBenchmark() ...@@ -117,7 +145,7 @@ void LinkProgramBenchmark::drawBenchmark()
ASSERT_NE(0u, vs); ASSERT_NE(0u, vs);
ASSERT_NE(0u, fs); ASSERT_NE(0u, fs);
if (GetParam().option == LinkProgramOption::CompileOnly) if (GetParam().taskOption == TaskOption::CompileOnly)
{ {
glDeleteShader(vs); glDeleteShader(vs);
glDeleteShader(fs); glDeleteShader(fs);
...@@ -146,30 +174,30 @@ void LinkProgramBenchmark::drawBenchmark() ...@@ -146,30 +174,30 @@ void LinkProgramBenchmark::drawBenchmark()
using namespace egl_platform; using namespace egl_platform;
LinkProgramParams LinkProgramD3D11Params(LinkProgramOption option) LinkProgramParams LinkProgramD3D11Params(TaskOption taskOption, ThreadOption threadOption)
{ {
LinkProgramParams params(option); LinkProgramParams params(taskOption, threadOption);
params.eglParameters = D3D11(); params.eglParameters = D3D11();
return params; return params;
} }
LinkProgramParams LinkProgramD3D9Params(LinkProgramOption option) LinkProgramParams LinkProgramD3D9Params(TaskOption taskOption, ThreadOption threadOption)
{ {
LinkProgramParams params(option); LinkProgramParams params(taskOption, threadOption);
params.eglParameters = D3D9(); params.eglParameters = D3D9();
return params; 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); params.eglParameters = OPENGL_OR_GLES(false);
return params; return params;
} }
LinkProgramParams LinkProgramVulkanParams(LinkProgramOption option) LinkProgramParams LinkProgramVulkanParams(TaskOption taskOption, ThreadOption threadOption)
{ {
LinkProgramParams params(option); LinkProgramParams params(taskOption, threadOption);
params.eglParameters = VULKAN(); params.eglParameters = VULKAN();
return params; return params;
} }
...@@ -179,14 +207,23 @@ TEST_P(LinkProgramBenchmark, Run) ...@@ -179,14 +207,23 @@ TEST_P(LinkProgramBenchmark, Run)
run(); run();
} }
ANGLE_INSTANTIATE_TEST(LinkProgramBenchmark, ANGLE_INSTANTIATE_TEST(
LinkProgramD3D11Params(LinkProgramOption::CompileOnly), LinkProgramBenchmark,
LinkProgramD3D9Params(LinkProgramOption::CompileOnly), LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramOpenGLOrGLESParams(LinkProgramOption::CompileOnly), LinkProgramD3D9Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramVulkanParams(LinkProgramOption::CompileOnly), LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramD3D11Params(LinkProgramOption::CompileAndLink), LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
LinkProgramD3D9Params(LinkProgramOption::CompileAndLink), LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
LinkProgramOpenGLOrGLESParams(LinkProgramOption::CompileAndLink), LinkProgramD3D9Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
LinkProgramVulkanParams(LinkProgramOption::CompileAndLink)); 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 } // anonymous namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment