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,
// The code gets compiled into binaries.
angle::Result Program::link(const Context *context)
{
ASSERT(mLinkResolved);
const auto &data = context->getState();
auto *platform = ANGLEPlatformCurrent();
......
......@@ -108,17 +108,20 @@ class ScopedExit final : angle::NonCopyable
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 @@ class CompileTask : public angle::Closure
}
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 @@ class CompileTask : public angle::Closure
std::string mSourcePath;
std::string mSource;
ShCompileOptions mOptions;
CompileImplFunctor mCompileImplFunctor;
bool mResult;
};
......@@ -385,9 +393,21 @@ void Shader::compile(const Context *context)
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);
}
......
......@@ -49,6 +49,7 @@ class SingleThreadedWorkerPool final : public WorkerThreadPool
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 @@ std::shared_ptr<WaitableEvent> SingleThreadedWorkerPool::postWorkerTask(
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 @@ class AsyncWorkerPool final : public WorkerThreadPool
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 @@ void AsyncWorkerPool::setMaxThreads(size_t maxThreads)
checkToRunPendingTasks();
}
bool AsyncWorkerPool::isAsync()
{
return true;
}
void AsyncWorkerPool::checkToRunPendingTasks()
{
std::lock_guard<std::mutex> lock(mMutex);
......
......@@ -68,6 +68,8 @@ class WorkerThreadPool : angle::NonCopyable
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
......
......@@ -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.
......
......@@ -27,6 +27,10 @@ class ShaderImpl : angle::NonCopyable
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;
......
......@@ -55,13 +55,13 @@ ShaderImpl *ContextGL::createShader(const gl::ShaderState &data)
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)
......
......@@ -228,6 +228,7 @@ class ContextGL : public ContextImpl
angle::Result setDrawIndirectState(const gl::Context *context);
protected:
std::shared_ptr<RendererGL> mRenderer;
};
......
......@@ -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 @@ ProgramGL::ProgramGL(const gl::ProgramState &data,
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 @@ void ProgramGL::setSeparable(bool separable)
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 @@ angle::Result ProgramGL::linkImpl(const gl::Context *context,
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 @@ 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);
// 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*/)
......
......@@ -19,6 +19,7 @@ namespace rx
{
class FunctionsGL;
class RendererGL;
class StateManagerGL;
class ProgramGL : public ProgramImpl
......@@ -28,7 +29,8 @@ class ProgramGL : public ProgramImpl
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 @@ class ProgramGL : public ProgramImpl
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 @@ class ProgramGL : public ProgramImpl
GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID;
std::shared_ptr<RendererGL> mRenderer;
bool mLinkedInParallel;
};
} // namespace rx
......
......@@ -222,6 +222,11 @@ RendererGL::~RendererGL()
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 @@ angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers)
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
......@@ -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 BlitGL;
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 @@ class RendererGL : angle::NonCopyable
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 @@ class RendererGL : angle::NonCopyable
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
......
......@@ -23,11 +23,13 @@ namespace rx
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 @@ ShaderGL::~ShaderGL()
void ShaderGL::destroy()
{
mFunctions->deleteShader(mShaderID);
mRenderer->getFunctions()->deleteShader(mShaderID);
mShaderID = 0;
}
......@@ -138,41 +140,70 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(const gl::Context *cont
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;
}
......
......@@ -13,7 +13,7 @@
namespace rx
{
class FunctionsGL;
class RendererGL;
struct WorkaroundsGL;
enum class MultiviewImplementationTypeGL;
......@@ -23,7 +23,7 @@ class ShaderGL : public ShaderImpl
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 @@ class ShaderGL : public ShaderImpl
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
......
......@@ -167,6 +167,11 @@ struct WorkaroundsGL
// 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;
......
......@@ -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 @@ class DisplayCGL : public DisplayGL
CGLContextObj getCGLContext() const;
WorkerContext *createWorkerContext(std::string *infoLog);
private:
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
......@@ -77,6 +84,7 @@ class DisplayCGL : public DisplayGL
egl::Display *mEGLDisplay;
CGLContextObj mContext;
CGLPixelFormatObj mPixelFormat;
};
} // namespace rx
......
......@@ -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 @@ class FunctionsGLCGL : public FunctionsGL
};
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 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
{
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 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
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 @@ egl::Error DisplayCGL::makeCurrentSurfaceless(gl::Context *context)
// 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);
}
}
//
// 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 @@
#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 @@ std::string DisplayEGL::getVendorString() const
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 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
if (context != EGL_NO_CONTEXT)
{
*outContext = context;
*outAttribs = attribList;
return egl::NoError();
}
}
......
......@@ -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 @@ class DisplayEGL : public DisplayGL
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;
......
......@@ -14,8 +14,12 @@ namespace rx
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 @@ EGLContext RendererEGL::getContext() const
return mContext;
}
WorkerContext *RendererEGL::createWorkerContext(std::string *infoLog)
{
return mDisplay->createWorkerContext(infoLog, mContext, mAttribs);
}
} // namespace rx
......@@ -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 @@ class RendererEGL : public RendererGL
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
......
......@@ -602,7 +602,8 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
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 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
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 &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
if (makeNewContextCurrent)
......@@ -634,4 +636,58 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
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
......@@ -78,6 +78,10 @@ class DisplayAndroid : public DisplayEGL
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;
......
......@@ -524,7 +524,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
}
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 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
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 @@ egl::Error DisplayOzone::makeCurrentSurfaceless(gl::Context *context)
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
......@@ -156,6 +156,10 @@ class DisplayOzone final : public DisplayEGL
// 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;
......
......@@ -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 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state)
: DisplayGL(state),
mRequestedVisual(-1),
mContextConfig(nullptr),
mVisuals(nullptr),
mContext(nullptr),
mSharedContext(nullptr),
mDummyPbuffer(0),
mUsesNewXDisplay(false),
mIsMesa(false),
......@@ -228,21 +230,21 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
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 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
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 @@ void DisplayGLX::terminate()
{
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 @@ int DisplayGLX::getGLXFBConfigAttrib(glx::FBConfig config, int attrib) const
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 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
// (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
......@@ -20,6 +20,7 @@ namespace rx
{
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 @@ class DisplayGLX : public DisplayGL
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 @@ class DisplayGLX : public DisplayGL
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 @@ class DisplayGLX : public DisplayGL
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;
......
//
// 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
workarounds->unsizedsRGBReadPixelsDoesntTransform = IsAndroid() && IsQualcomm(vendor);
workarounds->queryCounterBitsGeneratesErrors = IsNexus5X(vendor, device);
workarounds->dontRelinkProgramsInParallel = IsAndroid() || (IsWindows() && IsIntel(vendor));
}
void ApplyWorkarounds(const FunctionsGL *functions, gl::Workarounds *workarounds)
......
......@@ -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 @@ class DisplayWGL : public DisplayGL
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 @@ class DisplayWGL : public DisplayGL
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 @@ class DisplayWGL : public DisplayGL
size_t refCount;
};
std::map<IUnknown *, D3DObjectHandle> mRegisteredD3DDevices;
bool mHasWorkerContexts;
bool mUseARBShare;
};
} // namespace rx
......
......@@ -14,12 +14,22 @@ namespace rx
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 @@ HGLRC RendererWGL::getContext() const
return mContext;
}
WorkerContext *RendererWGL::createWorkerContext(std::string *infoLog)
{
return mDisplay->createWorkerContext(infoLog, mSharedContext, mWorkerContextAttribs);
}
} // namespace rx
......@@ -22,14 +22,19 @@ class RendererWGL : public RendererGL
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
......
......@@ -673,6 +673,8 @@ libangle_gl_glx_sources = [
"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 @@ libangle_gl_cgl_sources = [
"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",
......
......@@ -1912,7 +1912,9 @@ TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2)
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"
......
......@@ -19,7 +19,7 @@ using namespace angle;
namespace
{
enum class LinkProgramOption
enum class TaskOption
{
CompileOnly,
CompileAndLink,
......@@ -27,9 +27,17 @@ enum class LinkProgramOption
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 @@ struct LinkProgramParams final : public RenderTestParams
minorVersion = 0;
windowWidth = 256;
windowHeight = 256;
option = optionIn;
taskOption = taskOptionIn;
threadOption = threadOptionIn;
}
std::string suffix() const override
......@@ -45,10 +54,23 @@ struct LinkProgramParams final : public RenderTestParams
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 @@ struct LinkProgramParams final : public RenderTestParams
return strstr.str();
}
LinkProgramOption option;
TaskOption taskOption;
ThreadOption threadOption;
};
std::ostream &operator<<(std::ostream &os, const LinkProgramParams &params)
......@@ -85,6 +108,11 @@ LinkProgramBenchmark::LinkProgramBenchmark() : ANGLERenderTest("LinkProgram", Ge
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 @@ void LinkProgramBenchmark::drawBenchmark()
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 @@ void LinkProgramBenchmark::drawBenchmark()
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 @@ TEST_P(LinkProgramBenchmark, Run)
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
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