Commit 67bc1021 by Corentin Wallez

GLX backend: fallback to lesser swap_control extensions

Re-reland with a warning fix. We would like to use the EXT_swap_control extension to specify the swap interval of each drawable independently. However open source drivers do not expose this extension and instead expose the MESA and SGI versions that have a global swap interval. This commit changes the code to use the best swap_control extension it can, potentially changing the swap interval on each swap buffers on lesser extensions. BUG=angleproject:1206 Change-Id: I7ecf1eed6808672f277d0242d65f90d7851d2a32 Reviewed-on: https://chromium-review.googlesource.com/312322 Tryjob-Request: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 2075102d
......@@ -26,6 +26,13 @@ static int IgnoreX11Errors(Display *, XErrorEvent *)
return 0;
}
SwapControlData::SwapControlData()
: targetSwapInterval(0),
maxSwapInterval(-1),
currentSwapInterval(-1)
{
}
class FunctionsGLGLX : public FunctionsGL
{
public:
......@@ -55,6 +62,10 @@ DisplayGLX::DisplayGLX()
mDummyPbuffer(0),
mUsesNewXDisplay(false),
mIsMesa(false),
mSwapControl(SwapControl::Absent),
mMinSwapInterval(0),
mMaxSwapInterval(0),
mCurrentSwapInterval(-1),
mEGLDisplay(nullptr)
{
}
......@@ -102,6 +113,40 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
}
}
// Choose the swap_control extension to use, if any.
// The EXT version is better as it allows glXSwapInterval to be called per
// window, while we'll potentially need to change the swap interval on each
// swap buffers when using the SGI or MESA versions.
if (mGLX.hasExtension("GLX_EXT_swap_control"))
{
mSwapControl = SwapControl::EXT;
// In GLX_EXT_swap_control querying these is done on a GLXWindow so we just
// set default values.
mMinSwapInterval = 0;
mMaxSwapInterval = 4;
}
else if (mGLX.hasExtension("GLX_MESA_swap_control"))
{
// If we have the Mesa or SGI extension, assume that you can at least set
// a swap interval of 0 or 1.
mSwapControl = SwapControl::Mesa;
mMinSwapInterval = 0;
mMinSwapInterval = 1;
}
else if (mGLX.hasExtension("GLX_SGI_swap_control"))
{
mSwapControl = SwapControl::SGI;
mMinSwapInterval = 0;
mMinSwapInterval = 1;
}
else
{
mSwapControl = SwapControl::Absent;
mMinSwapInterval = 1;
mMinSwapInterval = 1;
}
// When glXMakeCurrent is called, the context and the surface must be
// compatible which in glX-speak means that their config have the same
// color buffer type, are both RGBA or ColorIndex, and their buffers have
......@@ -478,17 +523,9 @@ egl::ConfigSet DisplayGLX::generateConfigs() const
(glxDrawable & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0) |
(glxDrawable & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0);
if (hasSwapControl)
{
// In GLX_EXT_swap_control querying these is done on a GLXWindow so we just set a default value.
config.minSwapInterval = 0;
config.maxSwapInterval = 4;
}
else
{
config.minSwapInterval = 1;
config.maxSwapInterval = 1;
}
config.minSwapInterval = mMinSwapInterval;
config.maxSwapInterval = mMaxSwapInterval;
// TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway
config.renderTargetFormat = GL_RGBA8;
config.depthStencilFormat = GL_DEPTH24_STENCIL8;
......@@ -562,6 +599,49 @@ void DisplayGLX::syncXCommands() const
}
}
void DisplayGLX::setSwapInterval(glx::Drawable drawable, SwapControlData *data)
{
ASSERT(data != nullptr);
// TODO(cwallez) error checking?
if (mSwapControl == SwapControl::EXT)
{
// Prefer the EXT extension, it gives per-drawable swap intervals, which will
// minimize the number of driver calls.
if (data->maxSwapInterval < 0)
{
unsigned int maxSwapInterval = 0;
mGLX.queryDrawable(drawable, GLX_MAX_SWAP_INTERVAL_EXT, &maxSwapInterval);
data->maxSwapInterval = static_cast<int>(maxSwapInterval);
}
// When the egl configs were generated we had to guess what the max swap interval
// was because we didn't have a window to query it one (and that this max could
// depend on the monitor). This means that the target interval might be higher
// than the max interval and needs to be clamped.
const int realInterval = std::min(data->targetSwapInterval, data->maxSwapInterval);
if (data->currentSwapInterval != realInterval)
{
mGLX.swapIntervalEXT(drawable, realInterval);
data->currentSwapInterval = realInterval;
}
}
else if (mCurrentSwapInterval != data->targetSwapInterval)
{
// With the Mesa or SGI extensions we can still do per-drawable swap control
// manually but it is more expensive in number of driver calls.
if (mSwapControl == SwapControl::Mesa)
{
mGLX.swapIntervalMESA(data->targetSwapInterval);
}
else if (mSwapControl == SwapControl::Mesa)
{
mGLX.swapIntervalSGI(data->targetSwapInterval);
}
mCurrentSwapInterval = data->targetSwapInterval;
}
}
const FunctionsGL *DisplayGLX::getFunctionsGL() const
{
return mFunctionsGL;
......
......@@ -20,6 +20,20 @@ namespace rx
class FunctionsGLX;
// State-tracking data for the swap control to allow DisplayGLX to remember per
// drawable information for swap control.
struct SwapControlData
{
SwapControlData();
// Set by the drawable
int targetSwapInterval;
// DisplayGLX-side state-tracking
int maxSwapInterval;
int currentSwapInterval;
};
class DisplayGLX : public DisplayGL
{
public:
......@@ -59,6 +73,12 @@ class DisplayGLX : public DisplayGL
// between the application's display and ANGLE's one.
void syncXCommands() const;
// Depending on the supported GLX extension, swap interval can be set
// globally or per drawable. This function will make sure the drawable's
// swap interval is the one required so that the subsequent swapBuffers
// acts as expected.
void setSwapInterval(glx::Drawable drawable, SwapControlData *data);
private:
const FunctionsGL *getFunctionsGL() const override;
......@@ -83,6 +103,18 @@ class DisplayGLX : public DisplayGL
bool mUsesNewXDisplay;
bool mIsMesa;
enum class SwapControl
{
Absent,
EXT,
Mesa,
SGI,
};
SwapControl mSwapControl;
int mMinSwapInterval;
int mMaxSwapInterval;
int mCurrentSwapInterval;
FunctionsGLX mGLX;
egl::Display *mEGLDisplay;
};
......
......@@ -55,7 +55,9 @@ struct FunctionsGLX::GLXFunctionTable
destroyPbufferPtr(nullptr),
queryDrawablePtr(nullptr),
createContextAttribsARBPtr(nullptr),
swapIntervalEXTPtr(nullptr)
swapIntervalEXTPtr(nullptr),
swapIntervalMESAPtr(nullptr),
swapIntervalSGIPtr(nullptr)
{
}
......@@ -89,6 +91,12 @@ struct FunctionsGLX::GLXFunctionTable
// GLX_EXT_swap_control
PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr;
// GLX_MESA_swap_control
PFNGLXSWAPINTERVALMESAPROC swapIntervalMESAPtr;
// GLX_SGI_swap_control
PFNGLXSWAPINTERVALSGIPROC swapIntervalSGIPtr;
};
FunctionsGLX::FunctionsGLX()
......@@ -213,17 +221,17 @@ bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorS
{
GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB);
}
else
{
mFnPtrs->createContextAttribsARBPtr = nullptr;
}
if (hasExtension("GLX_EXT_swap_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalEXTPtr, glXSwapIntervalEXT);
}
else
if (hasExtension("GLX_MESA_swap_control"))
{
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalMESAPtr, glXSwapIntervalMESA);
}
if (hasExtension("GLX_SGI_swap_control"))
{
mFnPtrs->swapIntervalEXTPtr = nullptr;
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalSGIPtr, glXSwapIntervalSGI);
}
#undef GET_FNPTR_OR_ERROR
......@@ -360,4 +368,14 @@ void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const
mFnPtrs->swapIntervalEXTPtr(mXDisplay, drawable, intervals);
}
int FunctionsGLX::swapIntervalMESA(int intervals) const
{
return mFnPtrs->swapIntervalMESAPtr(intervals);
}
int FunctionsGLX::swapIntervalSGI(int intervals) const
{
return mFnPtrs->swapIntervalSGIPtr(intervals);
}
}
......@@ -67,6 +67,12 @@ class FunctionsGLX
// GLX_EXT_swap_control
void swapIntervalEXT(glx::Drawable drawable, int interval) const;
// GLX_MESA_swap_control
int swapIntervalMESA(int interval) const;
// GLX_SGI_swap_control
int swapIntervalSGI(int interval) const;
private:
// So as to isolate GLX from angle we do not include angleutils.h and cannot
// use angle::NonCopyable so we replicated it here instead.
......
......@@ -28,11 +28,10 @@ WindowSurfaceGLX::WindowSurfaceGLX(const FunctionsGLX &glx,
mWindow(0),
mDisplay(display),
mGLX(glx),
mGLXDisplay(*glxDisplay),
mGLXDisplay(glxDisplay),
mContext(context),
mFBConfig(fbConfig),
mGLXWindow(0),
mMaxSwapInterval(1)
mGLXWindow(0)
{
}
......@@ -48,7 +47,7 @@ WindowSurfaceGLX::~WindowSurfaceGLX()
XDestroyWindow(mDisplay, mWindow);
}
mGLXDisplay.syncXCommands();
mGLXDisplay->syncXCommands();
}
egl::Error WindowSurfaceGLX::initialize()
......@@ -95,18 +94,13 @@ egl::Error WindowSurfaceGLX::initialize()
0, visualInfo->depth, InputOutput, visual, attributeMask, &attributes);
mGLXWindow = mGLX.createWindow(mFBConfig, mWindow, nullptr);
if (mGLX.hasExtension("GLX_EXT_swap_control"))
{
mGLX.queryDrawable(mGLXWindow, GLX_MAX_SWAP_INTERVAL_EXT, &mMaxSwapInterval);
}
XMapWindow(mDisplay, mWindow);
XFlush(mDisplay);
XFree(visualInfo);
XFreeColormap(mDisplay, colormap);
mGLXDisplay.syncXCommands();
mGLXDisplay->syncXCommands();
return egl::Error(EGL_SUCCESS);
}
......@@ -140,6 +134,7 @@ egl::Error WindowSurfaceGLX::swap()
mGLX.waitX();
}
mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
mGLX.swapBuffers(mGLXWindow);
return egl::Error(EGL_SUCCESS);
......@@ -171,12 +166,7 @@ egl::Error WindowSurfaceGLX::releaseTexImage(EGLint buffer)
void WindowSurfaceGLX::setSwapInterval(EGLint interval)
{
if (mGLX.hasExtension("GLX_EXT_swap_control"))
{
// TODO(cwallez) error checking?
const int realInterval = std::min(interval, static_cast<int>(mMaxSwapInterval));
mGLX.swapIntervalEXT(mGLXWindow, realInterval);
}
mSwapControl.targetSwapInterval = interval;
}
EGLint WindowSurfaceGLX::getWidth() const
......
......@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/glx/DisplayGLX.h"
#include "libANGLE/renderer/gl/glx/platform_glx.h"
namespace rx
......@@ -55,12 +56,13 @@ class WindowSurfaceGLX : public SurfaceGL
Display *mDisplay;
const FunctionsGLX &mGLX;
const DisplayGLX &mGLXDisplay;
DisplayGLX *mGLXDisplay;
glx::Context mContext;
glx::FBConfig mFBConfig;
glx::Window mGLXWindow;
unsigned int mMaxSwapInterval;
SwapControlData mSwapControl;
};
}
......
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