Commit 043fcf18 by Peng Huang Committed by Commit Bot

Support create ANGLE EGLContext from an external EGLContext

For Android WebView, Android creates an EGLContext, EGLSurface and FBO, and makeCurrent on them, and then calls WebView draw function to draw the WebView content on the current EGLSurface or binded FBO. So to use ANGLE in WebView, this CL adds a way to create ANGLE EGLContext from an external EGLContext, and save and restore GL state in eglMakeCurrent(). Bug: angleproject:5509 Change-Id: I874986813117f125e23e975ea1adc51ac5b3a631 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2615239 Commit-Queue: Peng Huang <penghuang@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 5635dbb9
......@@ -337,6 +337,13 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
#define EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE 0x348D
#endif /* EGL_ANGLE_display_semaphore_share_group */
#ifndef EGL_ANGLE_external_context_and_surface
#define EGL_ANGLE_external_context_and_surface 1
#define EGL_EXTERNAL_CONTEXT_ANGLE 0x348E
#define EGL_EXTERNAL_SURFACE_ANGLE 0x348F
#define EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE 0x3490
#endif /* EGL_ANGLE_external_context_and_surface */
// clang-format on
#endif // INCLUDE_EGL_EGLEXT_ANGLE_
......@@ -1438,6 +1438,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_NOK_texture_from_pixmap", textureFromPixmapNOK, &extensionStrings);
InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings);
InsertExtensionString("EGL_KHR_reusable_sync", reusableSyncKHR, &extensionStrings);
InsertExtensionString("EGL_ANGLE_external_context_and_surface", externalContextAndSurface, &extensionStrings);
// clang-format on
return extensionStrings;
......
......@@ -1193,6 +1193,9 @@ struct DisplayExtensions
// EGL_KHR_reusable_sync
bool reusableSyncKHR = false;
// EGL_ANGLE_external_context_and_surface
bool externalContextAndSurface = false;
};
struct DeviceExtensions
......
......@@ -281,6 +281,17 @@ bool IsColorMaskedOut(const BlendStateExt &blendStateExt, const GLint drawbuffer
ASSERT(static_cast<size_t>(drawbuffer) < blendStateExt.mMaxDrawBuffers);
return blendStateExt.getColorMaskIndexed(static_cast<size_t>(drawbuffer)) == 0;
}
bool GetIsExternal(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE);
}
bool GetSaveAndRestoreState(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE, EGL_FALSE) == EGL_TRUE);
}
} // anonymous namespace
thread_local Context *gCurrentValidContext = nullptr;
......@@ -339,7 +350,10 @@ Context::Context(egl::Display *display,
mThreadPool(nullptr),
mFrameCapture(new angle::FrameCapture),
mRefCount(0),
mOverlay(mImplementation.get())
mOverlay(mImplementation.get()),
mIsExternal(GetIsExternal(attribs)),
mSaveAndRestoreState(GetSaveAndRestoreState(attribs)),
mIsCurrent(false)
{
for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex;
uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex)
......@@ -675,6 +689,8 @@ egl::Error Context::makeCurrent(egl::Display *display,
if (!mHasBeenCurrent)
{
ASSERT(!mIsCurrent);
initialize();
initRendererString();
initVersionStrings();
......
......@@ -406,6 +406,10 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
bool isVertexArrayGenerated(VertexArrayID vertexArray) const;
bool isTransformFeedbackGenerated(TransformFeedbackID transformFeedback) const;
bool isExternal() const { return mIsExternal; }
bool saveAndRestoreState() const { return mSaveAndRestoreState; }
bool isCurrent() const { return mIsCurrent; }
void getBooleanvImpl(GLenum pname, GLboolean *params) const;
void getFloatvImpl(GLenum pname, GLfloat *params) const;
void getIntegervImpl(GLenum pname, GLint *params) const;
......@@ -772,7 +776,10 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
OverlayType mOverlay;
bool mIsCurrent = false;
const bool mIsExternal;
const bool mSaveAndRestoreState;
bool mIsCurrent;
};
// Thread-local current valid context bound to the thread.
......
......@@ -381,6 +381,11 @@ void FramebufferManager::setDefaultFramebuffer(Framebuffer *framebuffer)
mObjectMap.assign(Framebuffer::kDefaultDrawFramebufferHandle, framebuffer);
}
Framebuffer *FramebufferManager::getDefaultFramebuffer() const
{
return getFramebuffer(Framebuffer::kDefaultDrawFramebufferHandle);
}
void FramebufferManager::invalidateFramebufferCompletenessCache() const
{
for (const auto &framebuffer : mObjectMap)
......
......@@ -273,6 +273,7 @@ class FramebufferManager
FramebufferID createFramebuffer();
Framebuffer *getFramebuffer(FramebufferID handle) const;
void setDefaultFramebuffer(Framebuffer *framebuffer);
Framebuffer *getDefaultFramebuffer() const;
void invalidateFramebufferCompletenessCache() const;
......
......@@ -1688,6 +1688,11 @@ Framebuffer *State::getTargetFramebuffer(GLenum target) const
}
}
Framebuffer *State::getDefaultFramebuffer() const
{
return mFramebufferManager->getDefaultFramebuffer();
}
bool State::removeReadFramebufferBinding(FramebufferID framebuffer)
{
if (mReadFramebuffer != nullptr && mReadFramebuffer->id() == framebuffer)
......
......@@ -333,6 +333,7 @@ class State : angle::NonCopyable
Framebuffer *getTargetFramebuffer(GLenum target) const;
Framebuffer *getReadFramebuffer() const { return mReadFramebuffer; }
Framebuffer *getDrawFramebuffer() const { return mDrawFramebuffer; }
Framebuffer *getDefaultFramebuffer() const;
bool removeReadFramebufferBinding(FramebufferID framebuffer);
bool removeDrawFramebufferBinding(FramebufferID framebuffer);
......
......@@ -1317,6 +1317,14 @@ GLuint FramebufferGL::getFramebufferID() const
return mFramebufferID;
}
void FramebufferGL::updateDefaultFramebufferID(GLuint framebufferID)
{
// We only update framebufferID for a default frambuffer, and the framebufferID is created
// externally. ANGLE doesn't owne it.
ASSERT(isDefault());
mFramebufferID = framebufferID;
}
bool FramebufferGL::isDefault() const
{
return mIsDefault;
......
......@@ -87,6 +87,7 @@ class FramebufferGL : public FramebufferImpl
gl::Command command) override;
GLuint getFramebufferID() const;
void updateDefaultFramebufferID(GLuint framebufferID);
bool isDefault() const;
bool hasEmulatedAlphaChannelTextureAttachment() const;
......
......@@ -16,6 +16,7 @@
#include "libANGLE/renderer/gl/functionsgl_typedefs.h"
#include "platform/FeaturesGL.h"
#include <array>
#include <map>
namespace gl
......@@ -34,6 +35,86 @@ class TransformFeedbackGL;
class VertexArrayGL;
class QueryGL;
// TODO(penghuang): use gl::State?
struct ExternalContextState
{
GLint packAlignment;
GLint unpackAlignment;
GLenum vertexArrayBufferBinding;
GLenum elementArrayBufferBinding;
bool depthTest;
bool cullFace;
GLenum cullFaceMode;
std::array<bool, 4> colorMask;
gl::ColorF colorClear;
gl::ColorF blendColor;
GLfloat depthClear;
GLenum currentProgram;
GLenum depthFunc;
bool depthMask;
GLfloat depthRage[2];
GLenum frontFace;
GLfloat lineWidth;
GLfloat polygonOffsetFactor;
GLfloat polygonOffsetUnits;
GLfloat sampleCoverageValue;
bool sampleCoverageInvert;
GLenum blendEquationRgb;
GLenum blendEquationAlpha;
bool enableDither;
bool enablePolygonOffsetFill;
bool enableSampleAlphaToCoverage;
bool enableSampleCoverage;
bool multisampleEnabled;
bool blendEnabled;
GLenum blendSrcRgb;
GLenum blendSrcAlpha;
GLenum blendDestRgb;
GLenum blendDestAlpha;
GLenum activeTexture;
gl::Rectangle viewport;
bool scissorTest;
gl::Rectangle scissorBox;
struct StencilState
{
bool stencilTestEnabled;
GLenum stencilFrontFunc;
GLint stencilFrontRef;
GLenum stencilFrontMask;
GLenum stencilBackFunc;
GLint stencilBackRef;
GLenum stencilBackMask;
GLint stencilClear;
GLenum stencilFrontWritemask;
GLenum stencilBackWritemask;
GLenum stencilFrontFailOp;
GLenum stencilFrontZFailOp;
GLenum stencilFrontZPassOp;
GLenum stencilBackFailOp;
GLenum stencilBackZFailOp;
GLenum stencilBackZPassOp;
};
StencilState stencilState;
GLenum framebufferBinding;
struct TextureBindings
{
GLenum texture2d;
GLenum textureCubeMap;
GLenum textureExternalOES;
// TODO(boliu): TEXTURE_RECTANGLE_ARB
};
std::vector<TextureBindings> textureBindings;
GLenum vertexArrayBinding;
};
class StateManagerGL final : angle::NonCopyable
{
public:
......@@ -181,6 +262,9 @@ class StateManagerGL final : angle::NonCopyable
void validateState() const;
void syncFromNativeContext(const gl::Extensions &extensions, ExternalContextState *state);
void restoreNativeContext(const gl::Extensions &extensions, const ExternalContextState *state);
private:
void setTextureCubemapSeamlessEnabled(bool enabled);
......@@ -195,6 +279,12 @@ class StateManagerGL final : angle::NonCopyable
void updateDispatchIndirectBufferBinding(const gl::Context *context);
void updateDrawIndirectBufferBinding(const gl::Context *context);
template <typename T>
void get(GLenum name, T *value);
template <size_t n, typename T>
void get(GLenum name, std::array<T, n> *values);
void syncSamplersState(const gl::Context *context);
void syncTransformFeedbackState(const gl::Context *context);
......@@ -202,6 +292,40 @@ class StateManagerGL final : angle::NonCopyable
const gl::Program *program,
const gl::FramebufferState &drawFramebufferState) const;
void syncBlendFromNativeContext(const gl::Extensions &extensions, ExternalContextState *state);
void restoreBlendNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncFramebufferFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restoreFramebufferNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncPixelPackUnpackFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restorePixelPackUnpackNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncStencilFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restoreStencilNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncBufferBindingsFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restoreBufferBindingsNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncTextureUnitsFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restoreTextureUnitsNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
void syncVertexArraysFromNativeContext(const gl::Extensions &extensions,
ExternalContextState *state);
void restoreVertexArraysNativeContext(const gl::Extensions &extensions,
const ExternalContextState *state);
const FunctionsGL *mFunctions;
const angle::FeaturesGL &mFeatures;
......@@ -342,6 +466,7 @@ class StateManagerGL final : angle::NonCopyable
gl::State::DirtyBits mLocalDirtyBits;
gl::AttributesMask mLocalDirtyCurrentValues;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_STATEMANAGERGL_H_
......@@ -6,8 +6,12 @@
#include "libANGLE/renderer/gl/egl/ContextEGL.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
namespace rx
{
ContextEGL::ContextEGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererEGL> &renderer,
......@@ -17,8 +21,42 @@ ContextEGL::ContextEGL(const gl::State &state,
ContextEGL::~ContextEGL() {}
angle::Result ContextEGL::onMakeCurrent(const gl::Context *context)
{
if (!context->isCurrent() && context->isExternal())
{
if (!mExtState)
{
mExtState = std::make_unique<ExternalContextState>();
const auto &caps = getNativeCaps();
mExtState->textureBindings.resize(
static_cast<size_t>(caps.maxCombinedTextureImageUnits));
}
getStateManager()->syncFromNativeContext(getNativeExtensions(), mExtState.get());
// Use current FBO as the default framebuffer when the external context is current.
gl::Framebuffer *framebuffer = mState.getDefaultFramebuffer();
GetImplAs<FramebufferGL>(framebuffer)
->updateDefaultFramebufferID(mExtState->framebufferBinding);
}
return ContextGL::onMakeCurrent(context);
}
angle::Result ContextEGL::onUnMakeCurrent(const gl::Context *context)
{
if (context->saveAndRestoreState())
{
ASSERT(context->isExternal());
ASSERT(mExtState);
getStateManager()->restoreNativeContext(getNativeExtensions(), mExtState.get());
}
return ContextGL::onUnMakeCurrent(context);
}
EGLContext ContextEGL::getContext() const
{
return mRendererEGL->getContext();
}
} // namespace rx
......@@ -14,6 +14,9 @@
namespace rx
{
struct ExternalContextState;
class ContextEGL : public ContextGL
{
public:
......@@ -23,10 +26,14 @@ class ContextEGL : public ContextGL
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus);
~ContextEGL() override;
angle::Result onMakeCurrent(const gl::Context *context) override;
angle::Result onUnMakeCurrent(const gl::Context *context) override;
EGLContext getContext() const;
private:
std::shared_ptr<RendererEGL> mRendererEGL;
std::unique_ptr<ExternalContextState> mExtState;
};
} // namespace rx
......
......@@ -280,7 +280,7 @@ egl::Error DisplayEGL::initialize(egl::Display *display)
functionsGL->initialize(mDisplayAttributes);
mRenderer.reset(
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs));
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs, false));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
......@@ -751,7 +751,7 @@ egl::Error DisplayEGL::createRenderer(EGLContext shareContext,
functionsGL->initialize(mDisplayAttributes);
outRenderer->reset(
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs));
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs, false));
return egl::NoError();
}
......
......@@ -132,6 +132,9 @@ class DisplayEGL : public DisplayGL
{
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
// True if the current context is an external context. and both surface and context will be
// unset when an external context is current.
bool isExternalContext = false;
};
angle::HashMap<std::thread::id, CurrentNativeContext> mCurrentNativeContexts;
......
......@@ -45,6 +45,7 @@ struct FunctionsEGL::EGLDispatchTable
destroyContextPtr(nullptr),
destroySurfacePtr(nullptr),
getConfigAttribPtr(nullptr),
getCurrentSurfacePtr(nullptr),
getDisplayPtr(nullptr),
getErrorPtr(nullptr),
initializePtr(nullptr),
......@@ -59,6 +60,8 @@ struct FunctionsEGL::EGLDispatchTable
surfaceAttribPtr(nullptr),
swapIntervalPtr(nullptr),
getCurrentContextPtr(nullptr),
createImageKHRPtr(nullptr),
destroyImageKHRPtr(nullptr),
......@@ -93,6 +96,7 @@ struct FunctionsEGL::EGLDispatchTable
PFNEGLDESTROYCONTEXTPROC destroyContextPtr;
PFNEGLDESTROYSURFACEPROC destroySurfacePtr;
PFNEGLGETCONFIGATTRIBPROC getConfigAttribPtr;
PFNEGLGETCURRENTSURFACEPROC getCurrentSurfacePtr;
PFNEGLGETDISPLAYPROC getDisplayPtr;
PFNEGLGETERRORPROC getErrorPtr;
PFNEGLINITIALIZEPROC initializePtr;
......@@ -108,6 +112,9 @@ struct FunctionsEGL::EGLDispatchTable
PFNEGLSURFACEATTRIBPROC surfaceAttribPtr;
PFNEGLSWAPINTERVALPROC swapIntervalPtr;
// 1.4
PFNEGLGETCURRENTCONTEXTPROC getCurrentContextPtr;
// EGL_KHR_image
PFNEGLCREATEIMAGEKHRPROC createImageKHRPtr;
PFNEGLDESTROYIMAGEKHRPROC destroyImageKHRPtr;
......@@ -169,6 +176,7 @@ egl::Error FunctionsEGL::initialize(EGLNativeDisplayType nativeDisplay)
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyContextPtr, eglDestroyContext);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySurfacePtr, eglDestroySurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigAttribPtr, eglGetConfigAttrib);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentSurfacePtr, eglGetCurrentSurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getDisplayPtr, eglGetDisplay);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getErrorPtr, eglGetError);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->initializePtr, eglInitialize);
......@@ -201,6 +209,8 @@ egl::Error FunctionsEGL::initialize(EGLNativeDisplayType nativeDisplay)
return egl::Error(mFnPtrs->getErrorPtr(), "Failed to bind API in system egl");
}
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentContextPtr, eglGetCurrentContext);
const char *extensions = queryString(EGL_EXTENSIONS);
if (!extensions)
{
......@@ -333,6 +343,11 @@ EGLBoolean FunctionsEGL::getConfigAttrib(EGLConfig config, EGLint attribute, EGL
return mFnPtrs->getConfigAttribPtr(mEGLDisplay, config, attribute, value);
}
EGLSurface FunctionsEGL::getCurrentSurface(EGLint readdraw) const
{
return mFnPtrs->getCurrentSurfacePtr(readdraw);
}
EGLContext FunctionsEGL::createContext(EGLConfig config,
EGLContext share_context,
EGLint const *attrib_list) const
......@@ -402,6 +417,11 @@ EGLBoolean FunctionsEGL::swapInterval(EGLint interval) const
return mFnPtrs->swapIntervalPtr(mEGLDisplay, interval);
}
EGLContext FunctionsEGL::getCurrentContext() const
{
return mFnPtrs->getCurrentContextPtr();
}
EGLImageKHR FunctionsEGL::createImageKHR(EGLContext context,
EGLenum target,
EGLClientBuffer buffer,
......
......@@ -46,6 +46,7 @@ class FunctionsEGL
EGLint config_size,
EGLint *num_config) const;
EGLBoolean getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const;
EGLSurface getCurrentSurface(EGLint readdraw) const;
EGLContext createContext(EGLConfig config,
EGLContext share_context,
EGLint const *attrib_list) const;
......@@ -65,6 +66,8 @@ class FunctionsEGL
EGLBoolean surfaceAttrib(EGLSurface surface, EGLint attribute, EGLint value) const;
EGLBoolean swapInterval(EGLint interval) const;
EGLContext getCurrentContext() const;
EGLImageKHR createImageKHR(EGLContext context,
EGLenum target,
EGLClientBuffer buffer,
......
......@@ -15,17 +15,22 @@ RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
const egl::AttributeMap &attribMap,
DisplayEGL *display,
EGLContext context,
const native_egl::AttributeVector attribs)
const native_egl::AttributeVector attribs,
bool isExternalContext)
: RendererGL(std::move(functionsGL), attribMap, display),
mDisplay(display),
mContext(context),
mAttribs(attribs)
mAttribs(attribs),
mIsExternalContext(isExternalContext)
{}
RendererEGL::~RendererEGL()
{
if (!mIsExternalContext)
{
mDisplay->destroyNativeContext(mContext);
mContext = nullptr;
}
}
EGLContext RendererEGL::getContext() const
......
......@@ -23,7 +23,8 @@ class RendererEGL : public RendererGL
const egl::AttributeMap &attribMap,
DisplayEGL *display,
EGLContext context,
const native_egl::AttributeVector attribs);
const native_egl::AttributeVector attribs,
bool isExternalContext);
~RendererEGL() override;
EGLContext getContext() const;
......@@ -34,6 +35,7 @@ class RendererEGL : public RendererGL
DisplayEGL *mDisplay;
EGLContext mContext;
const native_egl::AttributeVector mAttribs;
const bool mIsExternalContext;
};
} // namespace rx
......
......@@ -237,4 +237,9 @@ egl::Error SurfaceEGL::getFrameTimestamps(EGLuint64KHR frameId,
return egl::NoError();
}
bool SurfaceEGL::isExternal() const
{
return false;
}
} // namespace rx
......@@ -58,6 +58,7 @@ class SurfaceEGL : public SurfaceGL
EGLnsecsANDROID *values) const override;
EGLSurface getSurface() const;
virtual bool isExternal() const;
protected:
const FunctionsEGL *mEGL;
......
......@@ -152,7 +152,7 @@ egl::Error DisplayAndroid::initialize(egl::Display *display)
mConfig = configWithFormat;
}
ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, &mRenderer));
ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, false, &mRenderer));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
......@@ -205,14 +205,19 @@ ContextImpl *DisplayAndroid::createContext(const gl::State &state,
const egl::AttributeMap &attribs)
{
std::shared_ptr<RendererEGL> renderer;
if (mVirtualizedContexts)
bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE;
if (mVirtualizedContexts && !usingExternalContext)
{
renderer = mRenderer;
}
else
{
EGLContext nativeShareContext = EGL_NO_CONTEXT;
if (shareContext)
if (usingExternalContext)
{
ASSERT(!shareContext);
}
else if (shareContext)
{
ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
nativeShareContext = shareContextEGL->getContext();
......@@ -221,7 +226,8 @@ ContextImpl *DisplayAndroid::createContext(const gl::State &state,
// 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);
egl::Error error =
createRenderer(nativeShareContext, false, usingExternalContext, &renderer);
if (error.isError())
{
ERR() << "Failed to create a shared renderer: " << error.getMessage();
......@@ -233,11 +239,67 @@ ContextImpl *DisplayAndroid::createContext(const gl::State &state,
RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED);
}
class ExternalSurfaceEGL : public SurfaceEGL
{
public:
ExternalSurfaceEGL(const egl::SurfaceState &state,
const FunctionsEGL *egl,
EGLConfig config,
EGLint width,
EGLint height)
: SurfaceEGL(state, egl, config), mWidth(width), mHeight(height)
{}
~ExternalSurfaceEGL() override = default;
egl::Error initialize(const egl::Display *display) override { return egl::NoError(); }
EGLint getSwapBehavior() const override { return EGL_BUFFER_DESTROYED; }
EGLint getWidth() const override { return mWidth; }
EGLint getHeight() const override { return mHeight; }
bool isExternal() const override { return true; }
private:
const EGLint mWidth;
const EGLint mHeight;
};
SurfaceImpl *DisplayAndroid::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
if (buftype == EGL_EXTERNAL_SURFACE_ANGLE)
{
ASSERT(clientBuffer == nullptr);
EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
// Use the ExternalSurfaceEGL, so ANGLE can know the framebuffer size.
return new ExternalSurfaceEGL(state, mEGL, EGL_NO_CONFIG_KHR, width, height);
}
return DisplayEGL::createPbufferFromClientBuffer(state, buftype, clientBuffer, attribs);
}
bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
{
return ANativeWindow_getFormat(window) >= 0;
}
egl::Error DisplayAndroid::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
if (buftype == EGL_EXTERNAL_SURFACE_ANGLE)
{
ASSERT(clientBuffer == nullptr);
return egl::NoError();
}
return DisplayEGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
}
egl::Error DisplayAndroid::validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
......@@ -290,6 +352,35 @@ egl::Error DisplayAndroid::makeCurrent(egl::Display *display,
newContext = contextEGL->getContext();
}
if (currentContext.isExternalContext || (context && context->isExternal()))
{
ASSERT(currentContext.context == EGL_NO_CONTEXT);
ASSERT(currentContext.surface == EGL_NO_SURFACE);
if (!currentContext.isExternalContext)
{
// Switch to an ANGLE external context.
ASSERT(context);
currentContext.isExternalContext = true;
// We only support using external surface with external context.
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
}
else
{
// We don't support switching surfaces for external context.
ASSERT(!context);
// Release the ANGLE external context.
ASSERT(newSurface == EGL_NO_CONTEXT);
ASSERT(newContext == EGL_NO_SURFACE);
currentContext.isExternalContext = false;
}
// Do not need to call eglMakeCurrent(), since we don't support swtiching EGLSurface for
// external context.
return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
}
// The context should never change when context virtualization is being used, even when a null
// context is being bound.
if (mVirtualizedContexts)
......@@ -341,27 +432,46 @@ void DisplayAndroid::generateExtensions(egl::DisplayExtensions *outExtensions) c
// Surfaceless can be support if the native driver supports it or we know that we are running on
// a single thread (mVirtualizedContexts == true)
outExtensions->surfacelessContext = mSupportsSurfaceless || mVirtualizedContexts;
outExtensions->externalContextAndSurface = true;
}
egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
bool isExternalContext,
std::shared_ptr<RendererEGL> *outRenderer)
{
EGLContext context = EGL_NO_CONTEXT;
native_egl::AttributeVector attribs;
ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
// If isExternalContext is true, the external context is current, so we don't need to make the
// mMockPbuffer current.
if (isExternalContext)
{
ASSERT(shareContext == EGL_NO_CONTEXT);
ASSERT(!makeNewContextCurrent);
// Should we consider creating a share context to avoid querying and restoring GL context
// state?
context = mEGL->getCurrentContext();
ASSERT(context != EGL_NO_CONTEXT);
// TODO: get the version from the current context.
attribs = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 0, EGL_NONE};
}
else
{
ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
if (mEGL->makeCurrent(mMockPbuffer, 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, attribs));
outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context,
attribs, isExternalContext));
CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
if (makeNewContextCurrent)
......@@ -369,7 +479,7 @@ egl::Error DisplayAndroid::createRenderer(EGLContext shareContext,
currentContext.surface = mMockPbuffer;
currentContext.context = context;
}
else
else if (!isExternalContext)
{
// Reset the current context back to the previous state
if (mEGL->makeCurrent(currentContext.surface, currentContext.context) == EGL_FALSE)
......
......@@ -34,8 +34,15 @@ class DisplayAndroid : public DisplayEGL
const egl::Config *configuration,
const gl::Context *shareContext,
const egl::AttributeMap &attribs) override;
SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) override;
bool isValidNativeWindow(EGLNativeWindowType window) const override;
egl::Error validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
egl::Error validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
......@@ -62,6 +69,7 @@ class DisplayAndroid : public DisplayEGL
egl::Error createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
bool isExternalContext,
std::shared_ptr<RendererEGL> *outRenderer);
bool mVirtualizedContexts;
......
......@@ -530,7 +530,7 @@ egl::Error DisplayGbm::initialize(egl::Display *display)
functionsGL->initialize(display->getAttributeMap());
mRenderer.reset(new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this,
context, attribs));
context, attribs, false));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
......
......@@ -1948,6 +1948,47 @@ bool ValidateCreateContext(const ValidationContext *val,
}
break;
case EGL_EXTERNAL_CONTEXT_ANGLE:
if (!display->getExtensions().externalContextAndSurface)
{
val->setError(EGL_BAD_ATTRIBUTE,
"Attribute "
"EGL_EXTERNAL_CONTEXT_ANGLE requires "
"EGL_ANGLE_external_context_and_surface.");
return false;
}
if (value != EGL_TRUE && value != EGL_FALSE)
{
val->setError(EGL_BAD_ATTRIBUTE,
"EGL_EXTERNAL_CONTEXT_ANGLE must "
"be either EGL_TRUE or EGL_FALSE.");
return false;
}
if (value == EGL_TRUE && shareContext)
{
val->setError(
EGL_BAD_ATTRIBUTE,
"EGL_EXTERNAL_CONTEXT_ANGLE doesn't allow creating with sharedContext.");
return false;
}
break;
case EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE:
if (!display->getExtensions().externalContextAndSurface)
{
val->setError(EGL_BAD_ATTRIBUTE,
"Attribute "
"EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE requires "
"EGL_ANGLE_external_context_and_surface.");
return false;
}
if (value != EGL_TRUE && value != EGL_FALSE)
{
val->setError(EGL_BAD_ATTRIBUTE,
"EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE must "
"be either EGL_TRUE or EGL_FALSE.");
return false;
}
break;
default:
val->setError(EGL_BAD_ATTRIBUTE, "Unknown attribute.");
return false;
......@@ -2380,6 +2421,21 @@ bool ValidateCreatePbufferFromClientBuffer(const ValidationContext *val,
return false;
}
break;
case EGL_EXTERNAL_SURFACE_ANGLE:
if (!display->getExtensions().externalContextAndSurface)
{
val->setError(EGL_BAD_ATTRIBUTE,
"Attribute "
"EGL_EXTERNAL_SURFACE_ANGLE requires "
"EGL_ANGLE_external_context_and_surface.");
return false;
}
if (buffer != nullptr)
{
val->setError(EGL_BAD_PARAMETER, "<buffer> must be null");
return false;
}
break;
default:
val->setError(EGL_BAD_PARAMETER);
......@@ -2397,10 +2453,11 @@ bool ValidateCreatePbufferFromClientBuffer(const ValidationContext *val,
case EGL_WIDTH:
case EGL_HEIGHT:
if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE &&
buftype != EGL_D3D_TEXTURE_ANGLE && buftype != EGL_IOSURFACE_ANGLE)
buftype != EGL_D3D_TEXTURE_ANGLE && buftype != EGL_IOSURFACE_ANGLE &&
buftype != EGL_EXTERNAL_SURFACE_ANGLE)
{
val->setError(EGL_BAD_PARAMETER,
"Width and Height are not supported for thie <buftype>");
"Width and Height are not supported for this <buftype>");
return false;
}
if (value < 0)
......
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