Commit 258e8718 by Geoff Lang Committed by Commit Bot

EGL: Support unvirtualized contexts and unsafe multithreading.

-Add a new renderer and context type to own native EGL contexts and handle destruction. -Track the current EGL surface and context per-thread. -Support unvirtualized contexts by creating a new context for every client context. BUG=angleproject:2464 Change-Id: Ib2efa1d88c771b4a78625e0e3546f6ed95678c91 Reviewed-on: https://chromium-review.googlesource.com/1110943 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 838f304d
//
// Copyright 2018 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.
//
#include "libANGLE/renderer/gl/egl/ContextEGL.h"
namespace rx
{
ContextEGL::ContextEGL(const gl::ContextState &state, const std::shared_ptr<RendererEGL> &renderer)
: ContextGL(state, renderer), mRenderer(renderer)
{
}
ContextEGL::~ContextEGL()
{
}
EGLContext ContextEGL::getContext() const
{
return mRenderer->getContext();
}
}
//
// Copyright 2018 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.
//
// ContextEGL.h: Context class for GL on Android/ChromeOS. Wraps a RendererEGL.
#ifndef LIBANGLE_RENDERER_GL_EGL_CONTEXTEGL_H_
#define LIBANGLE_RENDERER_GL_EGL_CONTEXTEGL_H_
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/egl/RendererEGL.h"
namespace rx
{
class ContextEGL : public ContextGL
{
public:
ContextEGL(const gl::ContextState &state, const std::shared_ptr<RendererEGL> &renderer);
~ContextEGL() override;
EGLContext getContext() const;
private:
std::shared_ptr<RendererEGL> mRenderer;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
......@@ -16,7 +16,7 @@ namespace rx
#define EGL_NO_CONFIG ((EGLConfig)0)
DisplayEGL::DisplayEGL(const egl::DisplayState &state)
: DisplayGL(state), mEGL(nullptr), mConfig(EGL_NO_CONFIG), mContext(EGL_NO_CONTEXT)
: DisplayGL(state), mEGL(nullptr), mConfig(EGL_NO_CONFIG)
{
}
......@@ -31,7 +31,9 @@ std::string DisplayEGL::getVendorString() const
return vendor;
}
egl::Error DisplayEGL::initializeContext(const egl::AttributeMap &eglAttributes)
egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes,
EGLContext *outContext) const
{
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
......@@ -82,11 +84,13 @@ egl::Error DisplayEGL::initializeContext(const egl::AttributeMap &eglAttributes)
contextAttribLists.push_back({EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE});
}
EGLContext context = EGL_NO_CONTEXT;
for (const auto &attribList : contextAttribLists)
{
mContext = mEGL->createContext(mConfig, EGL_NO_CONTEXT, attribList.data());
if (mContext != EGL_NO_CONTEXT)
context = mEGL->createContext(mConfig, shareContext, attribList.data());
if (context != EGL_NO_CONTEXT)
{
*outContext = context;
return egl::NoError();
}
}
......
......@@ -23,12 +23,15 @@ class DisplayEGL : public DisplayGL
std::string getVendorString() const override;
virtual void destroyNativeContext(EGLContext context) = 0;
protected:
egl::Error initializeContext(const egl::AttributeMap &eglAttributes);
egl::Error initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes,
EGLContext *outContext) const;
FunctionsEGL *mEGL;
EGLConfig mConfig;
EGLContext mContext;
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
......
//
// Copyright 2018 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.
//
#include "libANGLE/renderer/gl/egl/RendererEGL.h"
#include "libANGLE/renderer/gl/egl/DisplayEGL.h"
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)
{
}
RendererEGL::~RendererEGL()
{
mDisplay->destroyNativeContext(mContext);
mContext = nullptr;
}
EGLContext RendererEGL::getContext() const
{
return mContext;
}
} // namespace rx
//
// Copyright 2018 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.
//
// RendererEGL.h: Renderer class for GL on Android/ChromeOS. Owns an EGL context object.
#ifndef LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
#define LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
#include "libANGLE/renderer/gl/RendererGL.h"
namespace rx
{
class DisplayEGL;
class RendererEGL : public RendererGL
{
public:
RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayEGL *display,
EGLContext context);
~RendererEGL() override;
EGLContext getContext() const;
private:
DisplayEGL *mDisplay;
EGLContext mContext;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EGL_RENDEREREGL_H_
......@@ -9,12 +9,15 @@
#include <android/native_window.h>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/egl/ContextEGL.h"
#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
#include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h"
#include "libANGLE/renderer/gl/egl/RendererEGL.h"
#include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h"
#include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
......@@ -34,8 +37,12 @@ const char *GetEGLPath()
namespace rx
{
static constexpr bool kDefaultEGLVirtualizedContexts = true;
DisplayAndroid::DisplayAndroid(const egl::DisplayState &state)
: DisplayEGL(state), mDummyPbuffer(EGL_NO_SURFACE), mCurrentSurface(EGL_NO_SURFACE)
: DisplayEGL(state),
mVirtualizedContexts(kDefaultEGLVirtualizedContexts),
mDummyPbuffer(EGL_NO_SURFACE)
{
}
......@@ -45,10 +52,14 @@ DisplayAndroid::~DisplayAndroid()
egl::Error DisplayAndroid::initialize(egl::Display *display)
{
mDisplayAttributes = display->getAttributeMap();
mVirtualizedContexts =
ShouldUseVirtualizedContexts(mDisplayAttributes, kDefaultEGLVirtualizedContexts);
FunctionsEGLDL *egl = new FunctionsEGLDL();
mEGL = egl;
void *eglHandle = reinterpret_cast<void *>(display->getAttributeMap().get(
EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
void *eglHandle =
reinterpret_cast<void *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), GetEGLPath(), eglHandle));
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
......@@ -140,20 +151,7 @@ egl::Error DisplayAndroid::initialize(egl::Display *display)
mConfig = configWithFormat;
}
ANGLE_TRY(initializeContext(display->getAttributeMap()));
success = mEGL->makeCurrent(mDummyPbuffer, mContext);
if (success == EGL_FALSE)
{
return egl::EglNotInitialized()
<< "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
}
mCurrentSurface = mDummyPbuffer;
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(display->getAttributeMap());
mRenderer.reset(new RendererGL(std::move(functionsGL), display->getAttributeMap()));
ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, &mRenderer));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
......@@ -173,7 +171,6 @@ void DisplayAndroid::terminate()
{
ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
}
mCurrentSurface = EGL_NO_SURFACE;
if (mDummyPbuffer != EGL_NO_SURFACE)
{
......@@ -186,15 +183,7 @@ void DisplayAndroid::terminate()
}
mRenderer.reset();
if (mContext != EGL_NO_CONTEXT)
{
success = mEGL->destroyContext(mContext);
mContext = EGL_NO_CONTEXT;
if (success == EGL_FALSE)
{
ERR() << "eglDestroyContext error " << egl::Error(mEGL->getError());
}
}
mCurrentNativeContext.clear();
egl::Error result = mEGL->terminate();
if (result.isError())
......@@ -264,7 +253,32 @@ ContextImpl *DisplayAndroid::createContext(const gl::ContextState &state,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
return new ContextGL(state, mRenderer);
std::shared_ptr<RendererEGL> renderer;
if (mVirtualizedContexts)
{
renderer = mRenderer;
}
else
{
EGLContext nativeShareContext = EGL_NO_CONTEXT;
if (shareContext)
{
ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
nativeShareContext = shareContextEGL->getContext();
}
// Create a new renderer for this context. It only needs to share with the user's requested
// share context because there are no internal resources in DisplayAndroid that are shared
// at the GL level.
egl::Error error = createRenderer(nativeShareContext, false, &renderer);
if (error.isError())
{
ERR() << "Failed to create a shared renderer: " << error.getMessage();
return nullptr;
}
}
return new ContextEGL(state, renderer);
}
template <typename T>
......@@ -456,22 +470,45 @@ egl::Error DisplayAndroid::waitNative(const gl::Context *context, EGLint engine)
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error DisplayAndroid::makeCurrent(egl::Surface *drawSurface,
egl::Surface *readSurface,
gl::Context *context)
{
CurrentNativeContext &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
EGLSurface newSurface = EGL_NO_SURFACE;
if (drawSurface)
{
SurfaceEGL *drawSurfaceEGL = GetImplAs<SurfaceEGL>(drawSurface);
EGLSurface surface = drawSurfaceEGL->getSurface();
if (surface != mCurrentSurface)
newSurface = drawSurfaceEGL->getSurface();
}
EGLContext newContext = EGL_NO_CONTEXT;
if (context)
{
ContextEGL *contextEGL = GetImplAs<ContextEGL>(context);
newContext = contextEGL->getContext();
}
// The context should never change when context virtualization is being used, even when a null
// context is being bound.
if (mVirtualizedContexts)
{
ASSERT(newContext == EGL_NO_CONTEXT || currentContext.context == EGL_NO_CONTEXT ||
newContext == currentContext.context);
newContext = mRenderer->getContext();
}
if (newSurface != currentContext.surface || newContext != currentContext.context)
{
if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
{
if (mEGL->makeCurrent(surface, mContext) == EGL_FALSE)
{
return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
}
mCurrentSurface = surface;
return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
}
currentContext.surface = newSurface;
currentContext.context = newContext;
}
return DisplayGL::makeCurrent(drawSurface, readSurface, context);
......@@ -482,6 +519,22 @@ gl::Version DisplayAndroid::getMaxSupportedESVersion() const
return mRenderer->getMaxSupportedESVersion();
}
void DisplayAndroid::destroyNativeContext(EGLContext context)
{
mEGL->destroyContext(context);
// If this context is current, remove it from the tracking of current contexts to make sure we
// don't try to make it current again.
for (auto &currentContext : mCurrentNativeContext)
{
if (currentContext.second.context == context)
{
currentContext.second.surface = EGL_NO_SURFACE;
currentContext.second.context = EGL_NO_CONTEXT;
}
}
}
egl::Error DisplayAndroid::makeCurrentSurfaceless(gl::Context *context)
{
// Nothing to do because EGL always uses the same context and the previous surface can be left
......@@ -489,4 +542,41 @@ egl::Error DisplayAndroid::makeCurrentSurfaceless(gl::Context *context)
return egl::NoError();
}
egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
std::shared_ptr<RendererEGL> *outRenderer)
{
EGLContext context = EGL_NO_CONTEXT;
ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context));
if (mEGL->makeCurrent(mDummyPbuffer, context) == EGL_FALSE)
{
return egl::EglNotInitialized()
<< "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
}
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(mDisplayAttributes);
outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context));
CurrentNativeContext &currentContext = mCurrentNativeContext[std::this_thread::get_id()];
if (makeNewContextCurrent)
{
currentContext.surface = mDummyPbuffer;
currentContext.context = context;
}
else
{
// Reset the current context back to the previous state
if (mEGL->makeCurrent(currentContext.surface, currentContext.context) == EGL_FALSE)
{
return egl::EglNotInitialized()
<< "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
}
}
return egl::NoError();
}
} // namespace rx
......@@ -11,6 +11,7 @@
#include <map>
#include <string>
#include <thread>
#include <vector>
#include "libANGLE/renderer/gl/egl/DisplayEGL.h"
......@@ -18,6 +19,8 @@
namespace rx
{
class RendererEGL;
class DisplayAndroid : public DisplayEGL
{
public:
......@@ -67,7 +70,13 @@ class DisplayAndroid : public DisplayEGL
gl::Version getMaxSupportedESVersion() const override;
void destroyNativeContext(EGLContext context) override;
private:
egl::Error createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
std::shared_ptr<RendererEGL> *outRenderer);
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
template <typename T>
......@@ -80,12 +89,21 @@ class DisplayAndroid : public DisplayEGL
const char *extension,
const U &defaultValue) const;
std::shared_ptr<RendererGL> mRenderer;
bool mVirtualizedContexts;
std::shared_ptr<RendererEGL> mRenderer;
egl::AttributeMap mDisplayAttributes;
std::vector<EGLint> mConfigAttribList;
std::map<EGLint, EGLint> mConfigIds;
EGLSurface mDummyPbuffer;
EGLSurface mCurrentSurface;
struct CurrentNativeContext
{
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
};
std::unordered_map<std::thread::id, CurrentNativeContext> mCurrentNativeContext;
};
} // namespace rx
......
......@@ -26,6 +26,8 @@
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/egl/ContextEGL.h"
#include "libANGLE/renderer/gl/egl/DisplayEGL.h"
#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
#include "libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h"
#include "platform/Platform.h"
......@@ -524,9 +526,10 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
mConfig = config[0];
}
ANGLE_TRY(initializeContext(display->getAttributeMap()));
EGLContext context = EGL_NO_CONTEXT;
ANGLE_TRY(initializeContext(EGL_NO_CONTEXT, display->getAttributeMap(), &context));
if (!mEGL->makeCurrent(EGL_NO_SURFACE, mContext))
if (!mEGL->makeCurrent(EGL_NO_SURFACE, context))
{
return egl::EglNotInitialized() << "Could not make context current.";
}
......@@ -534,7 +537,8 @@ egl::Error DisplayOzone::initialize(egl::Display *display)
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(display->getAttributeMap());
mRenderer.reset(new RendererGL(std::move(functionsGL), display->getAttributeMap()));
mRenderer.reset(
new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this, context));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
......@@ -855,19 +859,14 @@ void DisplayOzone::terminate()
DisplayGL::terminate();
if (mContext)
{
// Mesa might crash if you terminate EGL with a context current
// then re-initialize EGL, so make our context not current.
mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
mEGL->destroyContext(mContext);
mContext = nullptr;
}
mRenderer.reset();
if (mEGL)
{
// Mesa might crash if you terminate EGL with a context current then re-initialize EGL, so
// make our context not current.
mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
ANGLE_SWALLOW_ERR(mEGL->terminate());
SafeDelete(mEGL);
}
......@@ -936,7 +935,8 @@ ContextImpl *DisplayOzone::createContext(const gl::ContextState &state,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
return new ContextGL(state, mRenderer);
// All contexts on Ozone are virtualized and share the same renderer.
return new ContextEGL(state, mRenderer);
}
DeviceImpl *DisplayOzone::createDevice()
......@@ -999,6 +999,11 @@ gl::Version DisplayOzone::getMaxSupportedESVersion() const
return mRenderer->getMaxSupportedESVersion();
}
void DisplayOzone::destroyNativeContext(EGLContext context)
{
mEGL->destroyContext(context);
}
void DisplayOzone::setSwapInterval(EGLSurface drawable, SwapControlData *data)
{
ASSERT(data != nullptr);
......
......@@ -28,6 +28,7 @@ namespace rx
{
class FramebufferGL;
class RendererEGL;
// TODO(fjhenigman) Implement swap control. The following struct will be used for that.
// State-tracking data for the swap control to allow DisplayOzone to remember per
......@@ -146,6 +147,8 @@ class DisplayOzone final : public DisplayEGL
gl::Version getMaxSupportedESVersion() const override;
void destroyNativeContext(EGLContext context) override;
// TODO(fjhenigman) Implement this.
// Swap interval can be set globally or per drawable.
// This function will make sure the drawable's swap interval is the
......@@ -168,7 +171,7 @@ class DisplayOzone final : public DisplayEGL
void *data);
void pageFlipHandler(unsigned int sequence, uint64_t tv);
std::shared_ptr<RendererGL> mRenderer;
std::shared_ptr<RendererEGL> mRenderer;
gbm_device *mGBM;
drmModeConnectorPtr mConnector;
......
......@@ -717,6 +717,8 @@
],
'libangle_gl_egl_sources':
[
'libANGLE/renderer/gl/egl/ContextEGL.cpp',
'libANGLE/renderer/gl/egl/ContextEGL.h',
'libANGLE/renderer/gl/egl/DisplayEGL.cpp',
'libANGLE/renderer/gl/egl/DisplayEGL.h',
'libANGLE/renderer/gl/egl/egl_utils.cpp',
......@@ -726,6 +728,8 @@
'libANGLE/renderer/gl/egl/functionsegl_typedefs.h',
'libANGLE/renderer/gl/egl/PbufferSurfaceEGL.cpp',
'libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h',
'libANGLE/renderer/gl/egl/RendererEGL.cpp',
'libANGLE/renderer/gl/egl/RendererEGL.h',
'libANGLE/renderer/gl/egl/SurfaceEGL.cpp',
'libANGLE/renderer/gl/egl/SurfaceEGL.h',
'libANGLE/renderer/gl/egl/WindowSurfaceEGL.cpp',
......
......@@ -29,7 +29,7 @@ class MultithreadingTest : public ANGLETest
setContextVirtualization(false);
}
bool platformSupportsMultithreading() const { return false; }
bool platformSupportsMultithreading() const { return (IsOpenGLES() && IsAndroid()); }
};
// Test that it's possible to make one context current on different threads
......
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