Commit 2cb66715 by Geoff Lang Committed by Commit Bot

EGL: Merge DisplayAndroid into DisplayEGL.

These two classes have a lot of duplicated code for no reason. Bug: angleproject:5563 Change-Id: Ia9d8efeb50f3e52ffb1df6a6e462efdb20fd4a9a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2636678 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarPeng Huang <penghuang@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 82337b00
...@@ -42,6 +42,15 @@ ImageImpl *DisplayGL::createImage(const egl::ImageState &state, ...@@ -42,6 +42,15 @@ ImageImpl *DisplayGL::createImage(const egl::ImageState &state,
return nullptr; return nullptr;
} }
SurfaceImpl *DisplayGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
}
StreamProducerImpl *DisplayGL::createStreamProducerD3DTexture( StreamProducerImpl *DisplayGL::createStreamProducerD3DTexture(
egl::Stream::ConsumerType consumerType, egl::Stream::ConsumerType consumerType,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
......
...@@ -38,6 +38,11 @@ class DisplayGL : public DisplayImpl ...@@ -38,6 +38,11 @@ class DisplayGL : public DisplayImpl
EGLenum target, EGLenum target,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) override;
StreamProducerImpl *createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType, StreamProducerImpl *createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
......
...@@ -33,16 +33,15 @@ rx::RobustnessVideoMemoryPurgeStatus GetRobustnessVideoMemoryPurge(const egl::At ...@@ -33,16 +33,15 @@ rx::RobustnessVideoMemoryPurgeStatus GetRobustnessVideoMemoryPurge(const egl::At
attribs.get(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_FALSE)); attribs.get(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_FALSE));
} }
EGLint ESBitFromPlatformAttrib(const rx::FunctionsEGL *egl, const EGLAttrib platformAttrib) std::vector<EGLint> RenderableTypesFromPlatformAttrib(const rx::FunctionsEGL *egl,
const EGLAttrib platformAttrib)
{ {
EGLint esBit = EGL_NONE; std::vector<EGLint> renderableTypes;
switch (platformAttrib) switch (platformAttrib)
{ {
case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
{ renderableTypes.push_back(EGL_OPENGL_BIT);
esBit = EGL_OPENGL_BIT;
break; break;
}
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
{ {
...@@ -50,16 +49,18 @@ EGLint ESBitFromPlatformAttrib(const rx::FunctionsEGL *egl, const EGLAttrib plat ...@@ -50,16 +49,18 @@ EGLint ESBitFromPlatformAttrib(const rx::FunctionsEGL *egl, const EGLAttrib plat
"Extension define must match core"); "Extension define must match core");
gl::Version eglVersion(egl->majorVersion, egl->minorVersion); gl::Version eglVersion(egl->majorVersion, egl->minorVersion);
esBit = (eglVersion >= gl::Version(1, 5) || egl->hasExtension("EGL_KHR_create_context")) if (eglVersion >= gl::Version(1, 5) || egl->hasExtension("EGL_KHR_create_context"))
? EGL_OPENGL_ES3_BIT {
: EGL_OPENGL_ES2_BIT; renderableTypes.push_back(EGL_OPENGL_ES3_BIT);
break; }
renderableTypes.push_back(EGL_OPENGL_ES2_BIT);
} }
break;
default: default:
break; break;
} }
return esBit; return renderableTypes;
} }
class WorkerContextEGL final : public rx::WorkerContext class WorkerContextEGL final : public rx::WorkerContext
...@@ -108,14 +109,10 @@ void WorkerContextEGL::unmakeCurrent() ...@@ -108,14 +109,10 @@ void WorkerContextEGL::unmakeCurrent()
namespace rx namespace rx
{ {
static constexpr bool kDefaultEGLVirtualizedContexts = true;
DisplayEGL::DisplayEGL(const egl::DisplayState &state) DisplayEGL::DisplayEGL(const egl::DisplayState &state)
: DisplayGL(state), : DisplayGL(state), mVirtualizedContexts(kDefaultEGLVirtualizedContexts)
mRenderer(nullptr),
mEGL(nullptr),
mConfig(EGL_NO_CONFIG_KHR),
mCurrentNativeContexts(),
mHasEXTCreateContextRobustness(false),
mHasNVRobustnessVideoMemoryPurge(false)
{} {}
DisplayEGL::~DisplayEGL() {} DisplayEGL::~DisplayEGL() {}
...@@ -133,6 +130,19 @@ EGLSyncImpl *DisplayEGL::createSync(const egl::AttributeMap &attribs) ...@@ -133,6 +130,19 @@ EGLSyncImpl *DisplayEGL::createSync(const egl::AttributeMap &attribs)
return new SyncEGL(attribs, mEGL); return new SyncEGL(attribs, mEGL);
} }
const char *DisplayEGL::getEGLPath() const
{
#if defined(ANGLE_PLATFORM_ANDROID)
# if defined(__LP64__)
return "/system/lib64/libEGL.so";
# else
return "/system/lib/libEGL.so";
# endif
#else
return "libEGL.so.1";
#endif
}
egl::Error DisplayEGL::initializeContext(EGLContext shareContext, egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes, const egl::AttributeMap &eglAttributes,
EGLContext *outContext, EGLContext *outContext,
...@@ -151,13 +161,16 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -151,13 +161,16 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
static_assert(EGL_CONTEXT_MINOR_VERSION == EGL_CONTEXT_MINOR_VERSION_KHR, static_assert(EGL_CONTEXT_MINOR_VERSION == EGL_CONTEXT_MINOR_VERSION_KHR,
"Minor Version define should match"); "Minor Version define should match");
std::vector<native_egl::AttributeVector> contextAttribLists; std::vector<egl::AttributeMap> contextAttribLists;
if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context")) if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
{ {
if (initializeRequested) if (initializeRequested)
{ {
contextAttribLists.push_back({EGL_CONTEXT_MAJOR_VERSION, requestedMajor, egl::AttributeMap requestedVersionAttribs;
EGL_CONTEXT_MINOR_VERSION, requestedMinor}); requestedVersionAttribs.insert(EGL_CONTEXT_MAJOR_VERSION, requestedMajor);
requestedVersionAttribs.insert(EGL_CONTEXT_MINOR_VERSION, requestedMinor);
contextAttribLists.push_back(std::move(requestedVersionAttribs));
} }
else else
{ {
...@@ -172,9 +185,13 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -172,9 +185,13 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
for (const auto &version : esVersionsFrom2_0) for (const auto &version : esVersionsFrom2_0)
{ {
contextAttribLists.push_back( egl::AttributeMap versionAttribs;
{EGL_CONTEXT_MAJOR_VERSION, static_cast<EGLint>(version.major), versionAttribs.insert(EGL_CONTEXT_MAJOR_VERSION,
EGL_CONTEXT_MINOR_VERSION, static_cast<EGLint>(version.minor)}); static_cast<EGLint>(version.major));
versionAttribs.insert(EGL_CONTEXT_MINOR_VERSION,
static_cast<EGLint>(version.minor));
contextAttribLists.push_back(std::move(versionAttribs));
} }
} }
} }
...@@ -184,28 +201,48 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -184,28 +201,48 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
{ {
return egl::EglBadAttribute() << "Unsupported requested context version"; return egl::EglBadAttribute() << "Unsupported requested context version";
} }
contextAttribLists.push_back({EGL_CONTEXT_CLIENT_VERSION, 2});
egl::AttributeMap fallbackAttribs;
fallbackAttribs.insert(EGL_CONTEXT_CLIENT_VERSION, 2);
contextAttribLists.push_back(std::move(fallbackAttribs));
} }
EGLContext context = EGL_NO_CONTEXT; for (const egl::AttributeMap &attribs : contextAttribLists)
for (auto &attribList : contextAttribLists)
{ {
// If robustness is supported, try to create a context with robustness enabled. If it fails,
// fall back to creating a context without the robustness parameters. We've seen devices
// that expose the robustness extensions but fail to create robust contexts.
if (mHasEXTCreateContextRobustness) if (mHasEXTCreateContextRobustness)
{ {
attribList.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY); egl::AttributeMap attribsWithRobustness(attribs);
attribList.push_back(EGL_LOSE_CONTEXT_ON_RESET);
attribsWithRobustness.insert(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY,
EGL_LOSE_CONTEXT_ON_RESET);
if (mHasNVRobustnessVideoMemoryPurge) if (mHasNVRobustnessVideoMemoryPurge)
{ {
attribList.push_back(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV); attribsWithRobustness.insert(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE);
attribList.push_back(GL_TRUE);
} }
native_egl::AttributeVector attribVector = attribsWithRobustness.toIntVector();
EGLContext context = mEGL->createContext(mConfig, shareContext, attribVector.data());
if (context != EGL_NO_CONTEXT)
{
*outContext = context;
*outAttribs = std::move(attribVector);
return egl::NoError();
}
INFO() << "EGL_EXT_create_context_robustness available but robust context creation "
"failed.";
} }
attribList.push_back(EGL_NONE);
context = mEGL->createContext(mConfig, shareContext, attribList.data()); native_egl::AttributeVector attribVector = attribs.toIntVector();
EGLContext context = mEGL->createContext(mConfig, shareContext, attribVector.data());
if (context != EGL_NO_CONTEXT) if (context != EGL_NO_CONTEXT)
{ {
*outContext = context; *outContext = context;
*outAttribs = attribList; *outAttribs = std::move(attribVector);
return egl::NoError(); return egl::NoError();
} }
} }
...@@ -216,11 +253,13 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -216,11 +253,13 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
egl::Error DisplayEGL::initialize(egl::Display *display) egl::Error DisplayEGL::initialize(egl::Display *display)
{ {
mDisplayAttributes = display->getAttributeMap(); mDisplayAttributes = display->getAttributeMap();
mVirtualizedContexts =
ShouldUseVirtualizedContexts(mDisplayAttributes, kDefaultEGLVirtualizedContexts);
mEGL = new FunctionsEGLDL(); mEGL = new FunctionsEGLDL();
void *eglHandle = void *eglHandle =
reinterpret_cast<void *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0)); reinterpret_cast<void *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
ANGLE_TRY(mEGL->initialize(display->getNativeDisplayId(), "libEGL.so.1", eglHandle)); ANGLE_TRY(mEGL->initialize(display->getNativeDisplayId(), getEGLPath(), eglHandle));
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion); gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
if (eglVersion < gl::Version(1, 4)) if (eglVersion < gl::Version(1, 4))
...@@ -228,52 +267,83 @@ egl::Error DisplayEGL::initialize(egl::Display *display) ...@@ -228,52 +267,83 @@ egl::Error DisplayEGL::initialize(egl::Display *display)
return egl::EglNotInitialized() << "EGL >= 1.4 is required"; return egl::EglNotInitialized() << "EGL >= 1.4 is required";
} }
// Only support modern EGL implementation to keep default implementation
// simple.
const char *necessaryExtensions[] = {
"EGL_KHR_no_config_context",
"EGL_KHR_surfaceless_context",
};
for (const char *ext : necessaryExtensions)
{
if (!mEGL->hasExtension(ext))
{
return egl::EglNotInitialized() << "need " << ext;
}
}
mHasEXTCreateContextRobustness = mEGL->hasExtension("EGL_EXT_create_context_robustness"); mHasEXTCreateContextRobustness = mEGL->hasExtension("EGL_EXT_create_context_robustness");
mHasNVRobustnessVideoMemoryPurge = mEGL->hasExtension("EGL_NV_robustness_video_memory_purge"); mHasNVRobustnessVideoMemoryPurge = mEGL->hasExtension("EGL_NV_robustness_video_memory_purge");
const EGLAttrib platformAttrib = mDisplayAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, 0); const EGLAttrib platformAttrib = mDisplayAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, 0);
EGLint esBit = ESBitFromPlatformAttrib(mEGL, platformAttrib); std::vector<EGLint> renderableTypes = RenderableTypesFromPlatformAttrib(mEGL, platformAttrib);
if (esBit == EGL_NONE) if (renderableTypes.empty())
{ {
return egl::EglNotInitialized() << "No matching ES Bit"; return egl::EglNotInitialized() << "No available renderable types.";
} }
std::vector<EGLint> configAttribListBase = { egl::AttributeMap baseConfigAttribs;
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, baseConfigAttribs.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
EGL_CONFIG_CAVEAT, EGL_NONE, EGL_CONFORMANT, esBit, baseConfigAttribs.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
EGL_RENDERABLE_TYPE, esBit, EGL_NONE};
egl::AttributeMap configAttribsWithFormat(baseConfigAttribs);
// Choose RGBA8888
configAttribsWithFormat.insert(EGL_RED_SIZE, 8);
configAttribsWithFormat.insert(EGL_GREEN_SIZE, 8);
configAttribsWithFormat.insert(EGL_BLUE_SIZE, 8);
configAttribsWithFormat.insert(EGL_ALPHA_SIZE, 8);
// Choose D24S8
// EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
// must match for contexts to be compatible.
configAttribsWithFormat.insert(EGL_DEPTH_SIZE, 24);
configAttribsWithFormat.insert(EGL_STENCIL_SIZE, 8);
EGLConfig configWithFormat = EGL_NO_CONFIG_KHR;
for (EGLint renderableType : renderableTypes)
{
baseConfigAttribs.insert(EGL_RENDERABLE_TYPE, renderableType);
configAttribsWithFormat.insert(EGL_RENDERABLE_TYPE, renderableType);
mConfigAttribList = configAttribListBase; std::vector<EGLint> attribVector = configAttribsWithFormat.toIntVector();
EGLContext context = EGL_NO_CONTEXT; EGLint numConfig = 0;
native_egl::AttributeVector attribs; if (mEGL->chooseConfig(attribVector.data(), &configWithFormat, 1, &numConfig) == EGL_TRUE)
ANGLE_TRY(initializeContext(EGL_NO_CONTEXT, mDisplayAttributes, &context, &attribs)); {
break;
}
}
if (!mEGL->makeCurrent(EGL_NO_SURFACE, context)) if (configWithFormat == EGL_NO_CONFIG_KHR)
{ {
return egl::EglNotInitialized() << "Could not make context current."; return egl::EglNotInitialized()
<< "eglChooseConfig failed with " << egl::Error(mEGL->getError());
} }
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL()); // A mock pbuffer is only needed if surfaceless contexts are not supported.
functionsGL->initialize(mDisplayAttributes); mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
if (!mSupportsSurfaceless)
{
int mockPbufferAttribs[] = {
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
};
mMockPbuffer = mEGL->createPbufferSurface(configWithFormat, mockPbufferAttribs);
if (mMockPbuffer == EGL_NO_SURFACE)
{
return egl::EglNotInitialized()
<< "eglCreatePbufferSurface failed with " << egl::Error(mEGL->getError());
}
}
// Create mMockPbuffer with a normal config, but create a no_config mContext, if possible
if (mEGL->hasExtension("EGL_KHR_no_config_context"))
{
mConfigAttribList = baseConfigAttribs.toIntVector();
mConfig = EGL_NO_CONFIG_KHR;
}
else
{
mConfigAttribList = configAttribsWithFormat.toIntVector();
mConfig = configWithFormat;
}
ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, false, &mRenderer));
mRenderer.reset(
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs, false));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion(); const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0)) if (maxVersion < gl::Version(2, 0))
{ {
...@@ -282,6 +352,8 @@ egl::Error DisplayEGL::initialize(egl::Display *display) ...@@ -282,6 +352,8 @@ egl::Error DisplayEGL::initialize(egl::Display *display)
ANGLE_TRY(DisplayGL::initialize(display)); ANGLE_TRY(DisplayGL::initialize(display));
INFO() << "ANGLE DisplayEGL initialized: " << getRendererDescription();
return egl::NoError(); return egl::NoError();
} }
...@@ -295,6 +367,16 @@ void DisplayEGL::terminate() ...@@ -295,6 +367,16 @@ void DisplayEGL::terminate()
ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError()); ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
} }
if (mMockPbuffer != EGL_NO_SURFACE)
{
success = mEGL->destroySurface(mMockPbuffer);
mMockPbuffer = EGL_NO_SURFACE;
if (success == EGL_FALSE)
{
ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
}
}
mRenderer.reset(); mRenderer.reset();
mCurrentNativeContexts.clear(); mCurrentNativeContexts.clear();
...@@ -337,13 +419,44 @@ SurfaceImpl *DisplayEGL::createPbufferSurface(const egl::SurfaceState &state, ...@@ -337,13 +419,44 @@ SurfaceImpl *DisplayEGL::createPbufferSurface(const egl::SurfaceState &state,
return new PbufferSurfaceEGL(state, mEGL, config); return new PbufferSurfaceEGL(state, mEGL, config);
} }
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 *DisplayEGL::createPbufferFromClientBuffer(const egl::SurfaceState &state, SurfaceImpl *DisplayEGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype, EGLenum buftype,
EGLClientBuffer clientBuffer, EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
UNIMPLEMENTED(); switch (buftype)
return nullptr; {
case EGL_EXTERNAL_SURFACE_ANGLE:
return new ExternalSurfaceEGL(state, mEGL, EGL_NO_CONFIG_KHR,
attribs.getAsInt(EGL_WIDTH, 0),
attribs.getAsInt(EGL_HEIGHT, 0));
default:
return DisplayGL::createPbufferFromClientBuffer(state, buftype, clientBuffer, attribs);
}
} }
SurfaceImpl *DisplayEGL::createPixmapSurface(const egl::SurfaceState &state, SurfaceImpl *DisplayEGL::createPixmapSurface(const egl::SurfaceState &state,
...@@ -361,19 +474,35 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state, ...@@ -361,19 +474,35 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
std::shared_ptr<RendererEGL> renderer; std::shared_ptr<RendererEGL> renderer;
bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE;
if (mVirtualizedContexts && !usingExternalContext)
{
renderer = mRenderer;
}
else
{
EGLContext nativeShareContext = EGL_NO_CONTEXT; EGLContext nativeShareContext = EGL_NO_CONTEXT;
if (shareContext) if (usingExternalContext)
{
ASSERT(!shareContext);
}
else if (shareContext)
{ {
ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext); ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
nativeShareContext = shareContextEGL->getContext(); nativeShareContext = shareContextEGL->getContext();
} }
egl::Error error = createRenderer(nativeShareContext, &renderer); // 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 DisplayEGL that are shared
// at the GL level.
egl::Error error =
createRenderer(nativeShareContext, false, usingExternalContext, &renderer);
if (error.isError()) if (error.isError())
{ {
ERR() << "Failed to create a shared renderer: " << error.getMessage(); ERR() << "Failed to create a shared renderer: " << error.getMessage();
return nullptr; return nullptr;
} }
}
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus = RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
GetRobustnessVideoMemoryPurge(attribs); GetRobustnessVideoMemoryPurge(attribs);
...@@ -560,6 +689,22 @@ bool DisplayEGL::isValidNativeWindow(EGLNativeWindowType window) const ...@@ -560,6 +689,22 @@ bool DisplayEGL::isValidNativeWindow(EGLNativeWindowType window) const
return true; return true;
} }
egl::Error DisplayEGL::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
switch (buftype)
{
case EGL_EXTERNAL_SURFACE_ANGLE:
ASSERT(clientBuffer == nullptr);
return egl::NoError();
default:
return DisplayGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
}
}
egl::Error DisplayEGL::waitClient(const gl::Context *context) egl::Error DisplayEGL::waitClient(const gl::Context *context)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -593,6 +738,71 @@ egl::Error DisplayEGL::makeCurrent(egl::Display *display, ...@@ -593,6 +738,71 @@ egl::Error DisplayEGL::makeCurrent(egl::Display *display,
newContext = contextEGL->getContext(); newContext = contextEGL->getContext();
} }
if (currentContext.isExternalContext || (context && context->isExternal()))
{
ASSERT(currentContext.surface == EGL_NO_SURFACE);
if (!currentContext.isExternalContext)
{
// Switch to an ANGLE external context.
ASSERT(context);
ASSERT(currentContext.context == EGL_NO_CONTEXT);
currentContext.context = newContext;
currentContext.isExternalContext = true;
// We only support using external surface with external context.
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
}
else if (context)
{
// Switch surface but not context.
ASSERT(currentContext.context == newContext);
ASSERT(newSurface == EGL_NO_SURFACE);
ASSERT(newContext != EGL_NO_CONTEXT);
// We only support using external surface with external context.
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
}
else
{
// Release the ANGLE external context.
ASSERT(newSurface == EGL_NO_SURFACE);
ASSERT(newContext == EGL_NO_CONTEXT);
ASSERT(currentContext.context != EGL_NO_CONTEXT);
currentContext.context = EGL_NO_CONTEXT;
currentContext.isExternalContext = false;
}
// Do not need to call eglMakeCurrent(), since we don't support switching EGLSurface for
// external context.
return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
}
// The context should never change when context virtualization is being used unless binding a
// null context.
if (mVirtualizedContexts && newContext != EGL_NO_CONTEXT)
{
ASSERT(currentContext.context == EGL_NO_CONTEXT || newContext == currentContext.context);
newContext = mRenderer->getContext();
// If we know that we're only running on one thread (mVirtualizedContexts == true) and
// EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the
// surface binding and emulate the surfaceless extension in the frontend.
if (newSurface == EGL_NO_SURFACE)
{
newSurface = currentContext.surface;
}
// It's possible that no surface has been created yet and the driver doesn't support
// surfaceless, bind the mock pbuffer.
if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless)
{
newSurface = mMockPbuffer;
ASSERT(newSurface != EGL_NO_SURFACE);
}
}
if (newSurface != currentContext.surface || newContext != currentContext.context) if (newSurface != currentContext.surface || newContext != currentContext.context)
{ {
if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE) if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
...@@ -700,6 +910,12 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -700,6 +910,12 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge; outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
// 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;
DisplayGL::generateExtensions(outExtensions); DisplayGL::generateExtensions(outExtensions);
} }
...@@ -724,27 +940,57 @@ egl::Error DisplayEGL::makeCurrentSurfaceless(gl::Context *context) ...@@ -724,27 +940,57 @@ egl::Error DisplayEGL::makeCurrentSurfaceless(gl::Context *context)
} }
egl::Error DisplayEGL::createRenderer(EGLContext shareContext, egl::Error DisplayEGL::createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
bool isExternalContext,
std::shared_ptr<RendererEGL> *outRenderer) std::shared_ptr<RendererEGL> *outRenderer)
{ {
EGLContext context = EGL_NO_CONTEXT; EGLContext context = EGL_NO_CONTEXT;
native_egl::AttributeVector attribs; native_egl::AttributeVector attribs;
ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
if (mEGL->makeCurrent(EGL_NO_SURFACE, context) == EGL_FALSE) // 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);
// TODO(penghuang): Should we consider creating a share context to avoid querying and
// restoring GL context state? http://anglebug.com/5509
context = mEGL->getCurrentContext();
ASSERT(context != EGL_NO_CONTEXT);
// TODO(penghuang): get the version from the current context. http://anglebug.com/5509
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() return egl::EglNotInitialized()
<< "eglMakeCurrent failed with " << egl::Error(mEGL->getError()); << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
} }
}
CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
currentContext.surface = EGL_NO_SURFACE;
currentContext.context = context;
std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL()); std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
functionsGL->initialize(mDisplayAttributes); functionsGL->initialize(mDisplayAttributes);
outRenderer->reset( outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context,
new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context, attribs, false)); attribs, isExternalContext));
CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
if (makeNewContextCurrent)
{
currentContext.surface = mMockPbuffer;
currentContext.context = context;
}
else if (!isExternalContext)
{
// 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(); return egl::NoError();
} }
...@@ -774,7 +1020,7 @@ void DisplayEGL::populateFeatureList(angle::FeatureList *features) ...@@ -774,7 +1020,7 @@ void DisplayEGL::populateFeatureList(angle::FeatureList *features)
RendererGL *DisplayEGL::getRenderer() const RendererGL *DisplayEGL::getRenderer() const
{ {
return reinterpret_cast<RendererGL *>(mRenderer.get()); return mRenderer.get();
} }
egl::Error DisplayEGL::validateImageClientBuffer(const gl::Context *context, egl::Error DisplayEGL::validateImageClientBuffer(const gl::Context *context,
......
...@@ -73,6 +73,10 @@ class DisplayEGL : public DisplayGL ...@@ -73,6 +73,10 @@ class DisplayEGL : public DisplayGL
egl::Error restoreLostDevice(const egl::Display *display) override; egl::Error restoreLostDevice(const egl::Display *display) override;
bool isValidNativeWindow(EGLNativeWindowType window) const 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 waitClient(const gl::Context *context) override; egl::Error waitClient(const gl::Context *context) override;
egl::Error waitNative(const gl::Context *context, EGLint engine) override; egl::Error waitNative(const gl::Context *context, EGLint engine) override;
...@@ -100,7 +104,9 @@ class DisplayEGL : public DisplayGL ...@@ -100,7 +104,9 @@ class DisplayEGL : public DisplayGL
EGLClientBuffer buffer, EGLClientBuffer buffer,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
protected: private:
const char *getEGLPath() const;
egl::Error initializeContext(EGLContext shareContext, egl::Error initializeContext(EGLContext shareContext,
const egl::AttributeMap &eglAttributes, const egl::AttributeMap &eglAttributes,
EGLContext *outContext, EGLContext *outContext,
...@@ -108,7 +114,10 @@ class DisplayEGL : public DisplayGL ...@@ -108,7 +114,10 @@ class DisplayEGL : public DisplayGL
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
egl::Error createRenderer(EGLContext shareContext, std::shared_ptr<RendererEGL> *outRenderer); egl::Error createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
bool isExternalContext,
std::shared_ptr<RendererEGL> *outRenderer);
egl::Error makeCurrentSurfaceless(gl::Context *context) override; egl::Error makeCurrentSurfaceless(gl::Context *context) override;
...@@ -123,8 +132,8 @@ class DisplayEGL : public DisplayGL ...@@ -123,8 +132,8 @@ class DisplayEGL : public DisplayGL
const U &defaultValue) const; const U &defaultValue) const;
std::shared_ptr<RendererEGL> mRenderer; std::shared_ptr<RendererEGL> mRenderer;
FunctionsEGLDL *mEGL; FunctionsEGLDL *mEGL = nullptr;
EGLConfig mConfig; EGLConfig mConfig = EGL_NO_CONFIG_KHR;
egl::AttributeMap mDisplayAttributes; egl::AttributeMap mDisplayAttributes;
std::vector<EGLint> mConfigAttribList; std::vector<EGLint> mConfigAttribList;
...@@ -143,8 +152,14 @@ class DisplayEGL : public DisplayGL ...@@ -143,8 +152,14 @@ class DisplayEGL : public DisplayGL
std::map<EGLint, EGLint> mConfigIds; std::map<EGLint, EGLint> mConfigIds;
bool mHasEXTCreateContextRobustness; bool mHasEXTCreateContextRobustness = false;
bool mHasNVRobustnessVideoMemoryPurge; bool mHasNVRobustnessVideoMemoryPurge = false;
bool mVirtualizedContexts = false;
bool mSupportsSurfaceless = false;
EGLSurface mMockPbuffer = EGL_NO_SURFACE;
}; };
} // namespace rx } // namespace rx
......
...@@ -11,282 +11,21 @@ ...@@ -11,282 +11,21 @@
#include <android/log.h> #include <android/log.h>
#include <android/native_window.h> #include <android/native_window.h>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.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/RendererEGL.h"
#include "libANGLE/renderer/gl/egl/SurfaceEGL.h"
#include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h" #include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace
{
const char *GetEGLPath()
{
#if defined(__LP64__)
return "/system/lib64/libEGL.so";
#else
return "/system/lib/libEGL.so";
#endif
}
} // namespace
namespace rx namespace rx
{ {
static constexpr bool kDefaultEGLVirtualizedContexts = true; DisplayAndroid::DisplayAndroid(const egl::DisplayState &state) : DisplayEGL(state) {}
DisplayAndroid::DisplayAndroid(const egl::DisplayState &state)
: DisplayEGL(state),
mVirtualizedContexts(kDefaultEGLVirtualizedContexts),
mSupportsSurfaceless(false),
mMockPbuffer(EGL_NO_SURFACE)
{}
DisplayAndroid::~DisplayAndroid() {} 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 *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), GetEGLPath(), eglHandle));
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
ASSERT(eglVersion >= gl::Version(1, 4));
std::vector<EGLint> renderableTypes;
static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR, "Extension define must match core");
if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
{
renderableTypes.push_back(EGL_OPENGL_ES3_BIT);
}
renderableTypes.push_back(EGL_OPENGL_ES2_BIT);
egl::AttributeMap baseConfigAttribs;
baseConfigAttribs.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
// Android doesn't support pixmaps
baseConfigAttribs.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
egl::AttributeMap configAttribsWithFormat(baseConfigAttribs);
// Choose RGBA8888
configAttribsWithFormat.insert(EGL_RED_SIZE, 8);
configAttribsWithFormat.insert(EGL_GREEN_SIZE, 8);
configAttribsWithFormat.insert(EGL_BLUE_SIZE, 8);
configAttribsWithFormat.insert(EGL_ALPHA_SIZE, 8);
// Choose D24S8
// EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
// must match for contexts to be compatible.
configAttribsWithFormat.insert(EGL_DEPTH_SIZE, 24);
configAttribsWithFormat.insert(EGL_STENCIL_SIZE, 8);
EGLConfig configWithFormat = EGL_NO_CONFIG_KHR;
for (EGLint renderableType : renderableTypes)
{
baseConfigAttribs.insert(EGL_RENDERABLE_TYPE, renderableType);
configAttribsWithFormat.insert(EGL_RENDERABLE_TYPE, renderableType);
std::vector<EGLint> attribVector = configAttribsWithFormat.toIntVector();
EGLint numConfig = 0;
if (mEGL->chooseConfig(attribVector.data(), &configWithFormat, 1, &numConfig) == EGL_TRUE)
{
break;
}
}
if (configWithFormat == EGL_NO_CONFIG_KHR)
{
return egl::EglNotInitialized()
<< "eglChooseConfig failed with " << egl::Error(mEGL->getError());
}
// A mock pbuffer is only needed if surfaceless contexts are not supported.
mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
if (!mSupportsSurfaceless)
{
int mockPbufferAttribs[] = {
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
};
mMockPbuffer = mEGL->createPbufferSurface(configWithFormat, mockPbufferAttribs);
if (mMockPbuffer == EGL_NO_SURFACE)
{
return egl::EglNotInitialized()
<< "eglCreatePbufferSurface failed with " << egl::Error(mEGL->getError());
}
}
// Create mMockPbuffer with a normal config, but create a no_config mContext, if possible
if (mEGL->hasExtension("EGL_KHR_no_config_context"))
{
mConfigAttribList = baseConfigAttribs.toIntVector();
mConfig = EGL_NO_CONFIG_KHR;
}
else
{
mConfigAttribList = configAttribsWithFormat.toIntVector();
mConfig = configWithFormat;
}
ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, false, &mRenderer));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
}
ANGLE_TRY(DisplayGL::initialize(display));
std::string rendererDescription = getRendererDescription();
__android_log_print(ANDROID_LOG_INFO, "ANGLE", "%s", rendererDescription.c_str());
return egl::NoError();
}
void DisplayAndroid::terminate()
{
DisplayGL::terminate();
EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (success == EGL_FALSE)
{
ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
}
if (mMockPbuffer != EGL_NO_SURFACE)
{
success = mEGL->destroySurface(mMockPbuffer);
mMockPbuffer = EGL_NO_SURFACE;
if (success == EGL_FALSE)
{
ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
}
}
mRenderer.reset();
egl::Error result = mEGL->terminate();
if (result.isError())
{
ERR() << "eglTerminate error " << result;
}
SafeDelete(mEGL);
}
ContextImpl *DisplayAndroid::createContext(const gl::State &state,
gl::ErrorSet *errorSet,
const egl::Config *configuration,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
std::shared_ptr<RendererEGL> renderer;
bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE;
if (mVirtualizedContexts && !usingExternalContext)
{
renderer = mRenderer;
}
else
{
EGLContext nativeShareContext = EGL_NO_CONTEXT;
if (usingExternalContext)
{
ASSERT(!shareContext);
}
else 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, usingExternalContext, &renderer);
if (error.isError())
{
ERR() << "Failed to create a shared renderer: " << error.getMessage();
return nullptr;
}
}
return new ContextEGL(state, errorSet, renderer,
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 bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
{ {
return ANativeWindow_getFormat(window) >= 0; 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, egl::Error DisplayAndroid::validateImageClientBuffer(const gl::Context *context,
EGLenum target, EGLenum target,
EGLClientBuffer clientBuffer, EGLClientBuffer clientBuffer,
...@@ -318,229 +57,4 @@ ExternalImageSiblingImpl *DisplayAndroid::createExternalImageSibling( ...@@ -318,229 +57,4 @@ ExternalImageSiblingImpl *DisplayAndroid::createExternalImageSibling(
} }
} }
egl::Error DisplayAndroid::makeCurrent(egl::Display *display,
egl::Surface *drawSurface,
egl::Surface *readSurface,
gl::Context *context)
{
CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
EGLSurface newSurface = EGL_NO_SURFACE;
if (drawSurface)
{
SurfaceEGL *drawSurfaceEGL = GetImplAs<SurfaceEGL>(drawSurface);
newSurface = drawSurfaceEGL->getSurface();
}
EGLContext newContext = EGL_NO_CONTEXT;
if (context)
{
ContextEGL *contextEGL = GetImplAs<ContextEGL>(context);
newContext = contextEGL->getContext();
}
if (currentContext.isExternalContext || (context && context->isExternal()))
{
ASSERT(currentContext.surface == EGL_NO_SURFACE);
if (!currentContext.isExternalContext)
{
// Switch to an ANGLE external context.
ASSERT(context);
ASSERT(currentContext.context == EGL_NO_CONTEXT);
currentContext.context = newContext;
currentContext.isExternalContext = true;
// We only support using external surface with external context.
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
}
else if (context)
{
// Switch surface but not context.
ASSERT(currentContext.context == newContext);
ASSERT(newSurface == EGL_NO_SURFACE);
ASSERT(newContext != EGL_NO_CONTEXT);
// We only support using external surface with external context.
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
}
else
{
// Release the ANGLE external context.
ASSERT(newSurface == EGL_NO_SURFACE);
ASSERT(newContext == EGL_NO_CONTEXT);
ASSERT(currentContext.context != EGL_NO_CONTEXT);
currentContext.context = EGL_NO_CONTEXT;
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 unless binding a
// null context.
if (mVirtualizedContexts && newContext != EGL_NO_CONTEXT)
{
ASSERT(currentContext.context == EGL_NO_CONTEXT || newContext == currentContext.context);
newContext = mRenderer->getContext();
// If we know that we're only running on one thread (mVirtualizedContexts == true) and
// EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the
// surface binding and emulate the surfaceless extension in the frontend.
if (newSurface == EGL_NO_SURFACE)
{
newSurface = currentContext.surface;
}
// It's possible that no surface has been created yet and the driver doesn't support
// surfaceless, bind the mock pbuffer.
if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless)
{
newSurface = mMockPbuffer;
ASSERT(newSurface != EGL_NO_SURFACE);
}
}
if (newSurface != currentContext.surface || newContext != currentContext.context)
{
if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
{
return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
}
currentContext.surface = newSurface;
currentContext.context = newContext;
}
return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
}
void DisplayAndroid::destroyNativeContext(EGLContext context)
{
DisplayEGL::destroyNativeContext(context);
}
void DisplayAndroid::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
DisplayEGL::generateExtensions(outExtensions);
// 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;
// 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, isExternalContext));
CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
if (makeNewContextCurrent)
{
currentContext.surface = mMockPbuffer;
currentContext.context = context;
}
else if (!isExternalContext)
{
// 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();
}
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, mMockPbuffer);
}
} // namespace rx } // namespace rx
...@@ -26,23 +26,8 @@ class DisplayAndroid : public DisplayEGL ...@@ -26,23 +26,8 @@ class DisplayAndroid : public DisplayEGL
DisplayAndroid(const egl::DisplayState &state); DisplayAndroid(const egl::DisplayState &state);
~DisplayAndroid() override; ~DisplayAndroid() override;
egl::Error initialize(egl::Display *display) override;
void terminate() override;
ContextImpl *createContext(const gl::State &state,
gl::ErrorSet *errorSet,
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; 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, egl::Error validateImageClientBuffer(const gl::Context *context,
EGLenum target, EGLenum target,
EGLClientBuffer clientBuffer, EGLClientBuffer clientBuffer,
...@@ -52,31 +37,6 @@ class DisplayAndroid : public DisplayEGL ...@@ -52,31 +37,6 @@ class DisplayAndroid : public DisplayEGL
EGLenum target, EGLenum target,
EGLClientBuffer buffer, EGLClientBuffer buffer,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Display *display,
egl::Surface *drawSurface,
egl::Surface *readSurface,
gl::Context *context) override;
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;
egl::Error createRenderer(EGLContext shareContext,
bool makeNewContextCurrent,
bool isExternalContext,
std::shared_ptr<RendererEGL> *outRenderer);
bool mVirtualizedContexts;
bool mSupportsSurfaceless;
EGLSurface mMockPbuffer;
}; };
} // namespace rx } // namespace rx
......
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