Commit c295e516 by Corentin Wallez Committed by Commit Bot

Implement EGL_KHR_surfaceless_context

BUG=angleproject:1651 Change-Id: I710df14c2bfa55db2fb9b9715001756d1c1a8f1b Reviewed-on: https://chromium-review.googlesource.com/434763Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent bcb3f9ba
......@@ -1031,7 +1031,8 @@ DisplayExtensions::DisplayExtensions()
createContextWebGLCompatibility(false),
createContextBindGeneratesResource(false),
swapBuffersWithDamage(false),
pixelFormatFloat(false)
pixelFormatFloat(false),
surfacelessContext(false)
{
}
......@@ -1070,6 +1071,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_CHROMIUM_create_context_bind_generates_resource", createContextBindGeneratesResource, &extensionStrings);
InsertExtensionString("EGL_EXT_swap_buffers_with_damage", swapBuffersWithDamage, &extensionStrings);
InsertExtensionString("EGL_EXT_pixel_format_float", pixelFormatFloat, &extensionStrings);
InsertExtensionString("EGL_KHR_surfaceless_context", surfacelessContext, &extensionStrings);
// TODO(jmadill): Enable this when complete.
//InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
// clang-format on
......
......@@ -643,6 +643,9 @@ struct DisplayExtensions
// EGL_EXT_pixel_format_float
bool pixelFormatFloat;
// EGL_KHR_surfaceless_context
bool surfacelessContext;
};
struct DeviceExtensions
......
......@@ -20,7 +20,6 @@
#include "common/version.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Compiler.h"
#include "libANGLE/Display.h"
#include "libANGLE/Fence.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
......@@ -237,7 +236,8 @@ namespace gl
Context::Context(rx::EGLImplFactory *implFactory,
const egl::Config *config,
const Context *shareContext,
const egl::AttributeMap &attribs)
const egl::AttributeMap &attribs,
const egl::DisplayExtensions &displayExtensions)
: ValidationContext(shareContext,
GetClientVersion(attribs),
......@@ -265,7 +265,7 @@ Context::Context(rx::EGLImplFactory *implFactory,
UNIMPLEMENTED();
}
initCaps(GetWebGLContext(attribs));
initCaps(GetWebGLContext(attribs), displayExtensions);
initWorkarounds();
mGLState.initialize(mCaps, mExtensions, getClientVersion(), GetDebug(attribs),
......@@ -419,10 +419,7 @@ Context::~Context()
SafeDelete(mSurfacelessFramebuffer);
if (mCurrentSurface != nullptr)
{
releaseSurface();
}
releaseSurface();
SafeDelete(mCompiler);
}
......@@ -435,8 +432,16 @@ void Context::makeCurrent(egl::Surface *surface)
initVersionStrings();
initExtensionStrings();
mGLState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight());
mGLState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight());
int width = 0;
int height = 0;
if (surface != nullptr)
{
width = surface->getWidth();
height = surface->getHeight();
}
mGLState.setViewportParams(0, 0, width, height);
mGLState.setScissorParams(0, 0, width, height);
mHasBeenCurrent = true;
}
......@@ -444,10 +449,7 @@ void Context::makeCurrent(egl::Surface *surface)
// TODO(jmadill): Rework this when we support ContextImpl
mGLState.setAllDirtyBits();
if (mCurrentSurface)
{
releaseSurface();
}
releaseSurface();
Framebuffer *newDefault = nullptr;
if (surface != nullptr)
......@@ -486,24 +488,32 @@ void Context::makeCurrent(egl::Surface *surface)
void Context::releaseSurface()
{
ASSERT(mCurrentSurface != nullptr);
// Remove the default framebuffer
Framebuffer *currentDefault = nullptr;
if (mCurrentSurface != nullptr)
{
Framebuffer *currentDefault = mCurrentSurface->getDefaultFramebuffer();
if (mGLState.getReadFramebuffer() == currentDefault)
{
mGLState.setReadFramebufferBinding(nullptr);
}
if (mGLState.getDrawFramebuffer() == currentDefault)
{
mGLState.setDrawFramebufferBinding(nullptr);
}
mState.mFramebuffers->setDefaultFramebuffer(nullptr);
currentDefault = mCurrentSurface->getDefaultFramebuffer();
}
else if (mSurfacelessFramebuffer != nullptr)
{
currentDefault = mSurfacelessFramebuffer;
}
if (mGLState.getReadFramebuffer() == currentDefault)
{
mGLState.setReadFramebufferBinding(nullptr);
}
if (mGLState.getDrawFramebuffer() == currentDefault)
{
mGLState.setDrawFramebufferBinding(nullptr);
}
mState.mFramebuffers->setDefaultFramebuffer(nullptr);
mCurrentSurface->setIsCurrent(false);
mCurrentSurface = nullptr;
if (mCurrentSurface)
{
mCurrentSurface->setIsCurrent(false);
mCurrentSurface = nullptr;
}
}
GLuint Context::createBuffer()
......@@ -2378,7 +2388,7 @@ bool Context::hasActiveTransformFeedback(GLuint program) const
return false;
}
void Context::initCaps(bool webGLContext)
void Context::initCaps(bool webGLContext, const egl::DisplayExtensions &displayExtensions)
{
mCaps = mImplementation->getNativeCaps();
......@@ -2410,7 +2420,7 @@ void Context::initCaps(bool webGLContext)
mExtensions.noError = mSkipValidation;
// Enable surfaceless to advertise we'll have the correct behavior when there is no default FBO
mExtensions.surfacelessContext = true;
mExtensions.surfacelessContext = displayExtensions.surfacelessContext;
// Explicitly enable GL_KHR_debug
mExtensions.debug = true;
......
......@@ -61,7 +61,8 @@ class Context final : public ValidationContext
Context(rx::EGLImplFactory *implFactory,
const egl::Config *config,
const Context *shareContext,
const egl::AttributeMap &attribs);
const egl::AttributeMap &attribs,
const egl::DisplayExtensions &displayExtensions);
virtual ~Context();
......@@ -641,7 +642,7 @@ class Context final : public ValidationContext
void initVersionStrings();
void initExtensionStrings();
void initCaps(bool webGLContext);
void initCaps(bool webGLContext, const egl::DisplayExtensions &displayExtensions);
void updateCaps();
void initWorkarounds();
......
......@@ -673,7 +673,8 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont
ANGLE_TRY(restoreLostDevice());
}
gl::Context *context = new gl::Context(mImplementation, configuration, shareContext, attribs);
gl::Context *context =
new gl::Context(mImplementation, configuration, shareContext, attribs, mDisplayExtensions);
ASSERT(context != nullptr);
mContextSet.insert(context);
......@@ -687,7 +688,7 @@ Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface,
{
ANGLE_TRY(mImplementation->makeCurrent(drawSurface, readSurface, context));
if (context != nullptr && drawSurface != nullptr)
if (context != nullptr)
{
ASSERT(readSurface == drawSurface);
context->makeCurrent(drawSurface);
......
......@@ -81,7 +81,7 @@ egl::Error DisplayGL::makeCurrent(egl::Surface *drawSurface, egl::Surface *readS
}
mCurrentDrawSurface = nullptr;
if (!drawSurface)
if (!context)
{
return egl::Error(EGL_SUCCESS);
}
......@@ -90,11 +90,17 @@ egl::Error DisplayGL::makeCurrent(egl::Surface *drawSurface, egl::Surface *readS
ContextGL *glContext = GetImplAs<ContextGL>(context);
glContext->getStateManager()->pauseTransformFeedback();
SurfaceGL *glDrawSurface = GetImplAs<SurfaceGL>(drawSurface);
ANGLE_TRY(glDrawSurface->makeCurrent());
mCurrentDrawSurface = drawSurface;
return egl::Error(EGL_SUCCESS);
if (drawSurface != nullptr)
{
SurfaceGL *glDrawSurface = GetImplAs<SurfaceGL>(drawSurface);
ANGLE_TRY(glDrawSurface->makeCurrent());
mCurrentDrawSurface = drawSurface;
return egl::Error(EGL_SUCCESS);
}
else
{
return makeCurrentSurfaceless(context);
}
}
gl::Version DisplayGL::getMaxSupportedESVersion() const
......@@ -102,4 +108,10 @@ gl::Version DisplayGL::getMaxSupportedESVersion() const
ASSERT(mRenderer != nullptr);
return mRenderer->getMaxSupportedESVersion();
}
egl::Error DisplayGL::makeCurrentSurfaceless(gl::Context *context)
{
UNIMPLEMENTED();
return egl::NoError();
}
}
......@@ -51,6 +51,7 @@ class DisplayGL : public DisplayImpl
private:
virtual const FunctionsGL *getFunctionsGL() const = 0;
virtual egl::Error makeCurrentSurfaceless(gl::Context *context);
RendererGL *mRenderer;
......
......@@ -59,6 +59,7 @@ class DisplayCGL : public DisplayGL
private:
const FunctionsGL *getFunctionsGL() const override;
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
......
......@@ -245,6 +245,7 @@ const FunctionsGL *DisplayCGL::getFunctionsGL() const
void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->surfacelessContext = true;
}
void DisplayCGL::generateCaps(egl::Caps *outCaps) const
......@@ -271,4 +272,11 @@ egl::Error DisplayCGL::getDriverVersion(std::string *version) const
*version = "";
return egl::Error(EGL_SUCCESS);
}
egl::Error DisplayCGL::makeCurrentSurfaceless(gl::Context *context)
{
// We have nothing to do as mContext is always current, and that CGL is surfaceless by
// default.
return egl::NoError();
}
}
......@@ -828,6 +828,94 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
return Error(EGL_SUCCESS);
}
Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context)
{
if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
{
return Error(EGL_BAD_MATCH, "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE");
}
// If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
// error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE.
if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE))
{
if (display->getExtensions().surfacelessContext)
{
if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE))
{
return Error(EGL_BAD_MATCH,
"If ctx is not EGL_NOT_CONTEXT, draw or read must both be "
"EGL_NO_SURFACE, or both not");
}
}
else
{
return Error(EGL_BAD_MATCH,
"If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE");
}
}
// If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
// EGL_BAD_MATCH error is generated.
if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE))
{
return Error(EGL_BAD_MATCH,
"read and draw must both be valid surfaces, or both be EGL_NO_SURFACE");
}
if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
{
return Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle");
}
// EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
if (!display->isInitialized() &&
(context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
{
return Error(EGL_NOT_INITIALIZED, "'dpy' not initialized");
}
if (context != EGL_NO_CONTEXT)
{
ANGLE_TRY(ValidateContext(display, context));
}
if (display->isInitialized() && display->testDeviceLost())
{
return Error(EGL_CONTEXT_LOST);
}
Surface *drawSurface = static_cast<Surface *>(draw);
if (draw != EGL_NO_SURFACE)
{
ANGLE_TRY(ValidateSurface(display, drawSurface));
}
Surface *readSurface = static_cast<Surface *>(read);
if (read != EGL_NO_SURFACE)
{
ANGLE_TRY(ValidateSurface(display, readSurface));
}
if (readSurface)
{
ANGLE_TRY(ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface,
context->getConfig(), readSurface->getType()));
}
if (draw != read)
{
UNIMPLEMENTED(); // FIXME
if (drawSurface)
{
ANGLE_TRY(ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface,
context->getConfig(), drawSurface->getType()));
}
}
return egl::NoError();
}
Error ValidateCompatibleConfigs(const Display *display,
const Config *config1,
const Surface *surface,
......
......@@ -49,6 +49,8 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer,
Config *config, const AttributeMap& attributes);
Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context);
Error ValidateCreateImageKHR(const Display *display,
gl::Context *context,
EGLenum target,
......
......@@ -548,109 +548,15 @@ EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface r
Display *display = static_cast<Display*>(dpy);
gl::Context *context = static_cast<gl::Context*>(ctx);
// If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
// error is generated.
if (ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
{
thread->setError(Error(EGL_BAD_MATCH));
return EGL_FALSE;
}
if (ctx != EGL_NO_CONTEXT && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE)
{
thread->setError(Error(EGL_BAD_MATCH));
return EGL_FALSE;
}
// If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
// EGL_BAD_MATCH error is generated.
if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE))
{
thread->setError(Error(
EGL_BAD_MATCH, "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE"));
return EGL_FALSE;
}
if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
{
thread->setError(Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle"));
return EGL_FALSE;
}
// EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
if (!display->isInitialized() && (ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
{
thread->setError(Error(EGL_NOT_INITIALIZED, "'dpy' not initialized"));
return EGL_FALSE;
}
if (ctx != EGL_NO_CONTEXT)
{
Error error = ValidateContext(display, context);
if (error.isError())
{
thread->setError(error);
return EGL_FALSE;
}
}
if (display->isInitialized() && display->testDeviceLost())
Error error = ValidateMakeCurrent(display, draw, read, context);
if (error.isError())
{
thread->setError(Error(EGL_CONTEXT_LOST));
thread->setError(error);
return EGL_FALSE;
}
Surface *drawSurface = static_cast<Surface*>(draw);
if (draw != EGL_NO_SURFACE)
{
Error error = ValidateSurface(display, drawSurface);
if (error.isError())
{
thread->setError(error);
return EGL_FALSE;
}
}
Surface *readSurface = static_cast<Surface*>(read);
if (read != EGL_NO_SURFACE)
{
Error error = ValidateSurface(display, readSurface);
if (error.isError())
{
thread->setError(error);
return EGL_FALSE;
}
}
if (readSurface)
{
Error readCompatError =
ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface,
context->getConfig(), readSurface->getType());
if (readCompatError.isError())
{
thread->setError(readCompatError);
return EGL_FALSE;
}
}
if (draw != read)
{
UNIMPLEMENTED(); // FIXME
if (drawSurface)
{
Error drawCompatError =
ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface,
context->getConfig(), drawSurface->getType());
if (drawCompatError.isError())
{
thread->setError(drawCompatError);
return EGL_FALSE;
}
}
}
Surface *drawSurface = static_cast<Surface *>(draw);
Error makeCurrentError = display->makeCurrent(drawSurface, readSurface, context);
if (makeCurrentError.isError())
{
......
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