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 *) ...@@ -26,6 +26,13 @@ static int IgnoreX11Errors(Display *, XErrorEvent *)
return 0; return 0;
} }
SwapControlData::SwapControlData()
: targetSwapInterval(0),
maxSwapInterval(-1),
currentSwapInterval(-1)
{
}
class FunctionsGLGLX : public FunctionsGL class FunctionsGLGLX : public FunctionsGL
{ {
public: public:
...@@ -55,6 +62,10 @@ DisplayGLX::DisplayGLX() ...@@ -55,6 +62,10 @@ DisplayGLX::DisplayGLX()
mDummyPbuffer(0), mDummyPbuffer(0),
mUsesNewXDisplay(false), mUsesNewXDisplay(false),
mIsMesa(false), mIsMesa(false),
mSwapControl(SwapControl::Absent),
mMinSwapInterval(0),
mMaxSwapInterval(0),
mCurrentSwapInterval(-1),
mEGLDisplay(nullptr) mEGLDisplay(nullptr)
{ {
} }
...@@ -102,6 +113,40 @@ egl::Error DisplayGLX::initialize(egl::Display *display) ...@@ -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 // When glXMakeCurrent is called, the context and the surface must be
// compatible which in glX-speak means that their config have the same // compatible which in glX-speak means that their config have the same
// color buffer type, are both RGBA or ColorIndex, and their buffers have // color buffer type, are both RGBA or ColorIndex, and their buffers have
...@@ -478,17 +523,9 @@ egl::ConfigSet DisplayGLX::generateConfigs() const ...@@ -478,17 +523,9 @@ egl::ConfigSet DisplayGLX::generateConfigs() const
(glxDrawable & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0) | (glxDrawable & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0) |
(glxDrawable & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0); (glxDrawable & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0);
if (hasSwapControl) config.minSwapInterval = mMinSwapInterval;
{ config.maxSwapInterval = mMaxSwapInterval;
// 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;
}
// TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway // TODO(cwallez) wildly guessing these formats, another TODO says they should be removed anyway
config.renderTargetFormat = GL_RGBA8; config.renderTargetFormat = GL_RGBA8;
config.depthStencilFormat = GL_DEPTH24_STENCIL8; config.depthStencilFormat = GL_DEPTH24_STENCIL8;
...@@ -562,6 +599,49 @@ void DisplayGLX::syncXCommands() const ...@@ -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 const FunctionsGL *DisplayGLX::getFunctionsGL() const
{ {
return mFunctionsGL; return mFunctionsGL;
......
...@@ -20,6 +20,20 @@ namespace rx ...@@ -20,6 +20,20 @@ namespace rx
class FunctionsGLX; 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 class DisplayGLX : public DisplayGL
{ {
public: public:
...@@ -59,6 +73,12 @@ class DisplayGLX : public DisplayGL ...@@ -59,6 +73,12 @@ class DisplayGLX : public DisplayGL
// between the application's display and ANGLE's one. // between the application's display and ANGLE's one.
void syncXCommands() const; 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: private:
const FunctionsGL *getFunctionsGL() const override; const FunctionsGL *getFunctionsGL() const override;
...@@ -83,6 +103,18 @@ class DisplayGLX : public DisplayGL ...@@ -83,6 +103,18 @@ class DisplayGLX : public DisplayGL
bool mUsesNewXDisplay; bool mUsesNewXDisplay;
bool mIsMesa; bool mIsMesa;
enum class SwapControl
{
Absent,
EXT,
Mesa,
SGI,
};
SwapControl mSwapControl;
int mMinSwapInterval;
int mMaxSwapInterval;
int mCurrentSwapInterval;
FunctionsGLX mGLX; FunctionsGLX mGLX;
egl::Display *mEGLDisplay; egl::Display *mEGLDisplay;
}; };
......
...@@ -55,7 +55,9 @@ struct FunctionsGLX::GLXFunctionTable ...@@ -55,7 +55,9 @@ struct FunctionsGLX::GLXFunctionTable
destroyPbufferPtr(nullptr), destroyPbufferPtr(nullptr),
queryDrawablePtr(nullptr), queryDrawablePtr(nullptr),
createContextAttribsARBPtr(nullptr), createContextAttribsARBPtr(nullptr),
swapIntervalEXTPtr(nullptr) swapIntervalEXTPtr(nullptr),
swapIntervalMESAPtr(nullptr),
swapIntervalSGIPtr(nullptr)
{ {
} }
...@@ -89,6 +91,12 @@ struct FunctionsGLX::GLXFunctionTable ...@@ -89,6 +91,12 @@ struct FunctionsGLX::GLXFunctionTable
// GLX_EXT_swap_control // GLX_EXT_swap_control
PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr; PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr;
// GLX_MESA_swap_control
PFNGLXSWAPINTERVALMESAPROC swapIntervalMESAPtr;
// GLX_SGI_swap_control
PFNGLXSWAPINTERVALSGIPROC swapIntervalSGIPtr;
}; };
FunctionsGLX::FunctionsGLX() FunctionsGLX::FunctionsGLX()
...@@ -213,17 +221,17 @@ bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorS ...@@ -213,17 +221,17 @@ bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorS
{ {
GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB); GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB);
} }
else
{
mFnPtrs->createContextAttribsARBPtr = nullptr;
}
if (hasExtension("GLX_EXT_swap_control")) if (hasExtension("GLX_EXT_swap_control"))
{ {
GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalEXTPtr, glXSwapIntervalEXT); 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 #undef GET_FNPTR_OR_ERROR
...@@ -360,4 +368,14 @@ void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const ...@@ -360,4 +368,14 @@ void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const
mFnPtrs->swapIntervalEXTPtr(mXDisplay, drawable, intervals); 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 ...@@ -67,6 +67,12 @@ class FunctionsGLX
// GLX_EXT_swap_control // GLX_EXT_swap_control
void swapIntervalEXT(glx::Drawable drawable, int interval) const; 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: private:
// So as to isolate GLX from angle we do not include angleutils.h and cannot // So as to isolate GLX from angle we do not include angleutils.h and cannot
// use angle::NonCopyable so we replicated it here instead. // use angle::NonCopyable so we replicated it here instead.
......
...@@ -28,11 +28,10 @@ WindowSurfaceGLX::WindowSurfaceGLX(const FunctionsGLX &glx, ...@@ -28,11 +28,10 @@ WindowSurfaceGLX::WindowSurfaceGLX(const FunctionsGLX &glx,
mWindow(0), mWindow(0),
mDisplay(display), mDisplay(display),
mGLX(glx), mGLX(glx),
mGLXDisplay(*glxDisplay), mGLXDisplay(glxDisplay),
mContext(context), mContext(context),
mFBConfig(fbConfig), mFBConfig(fbConfig),
mGLXWindow(0), mGLXWindow(0)
mMaxSwapInterval(1)
{ {
} }
...@@ -48,7 +47,7 @@ WindowSurfaceGLX::~WindowSurfaceGLX() ...@@ -48,7 +47,7 @@ WindowSurfaceGLX::~WindowSurfaceGLX()
XDestroyWindow(mDisplay, mWindow); XDestroyWindow(mDisplay, mWindow);
} }
mGLXDisplay.syncXCommands(); mGLXDisplay->syncXCommands();
} }
egl::Error WindowSurfaceGLX::initialize() egl::Error WindowSurfaceGLX::initialize()
...@@ -95,18 +94,13 @@ egl::Error WindowSurfaceGLX::initialize() ...@@ -95,18 +94,13 @@ egl::Error WindowSurfaceGLX::initialize()
0, visualInfo->depth, InputOutput, visual, attributeMask, &attributes); 0, visualInfo->depth, InputOutput, visual, attributeMask, &attributes);
mGLXWindow = mGLX.createWindow(mFBConfig, mWindow, nullptr); 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); XMapWindow(mDisplay, mWindow);
XFlush(mDisplay); XFlush(mDisplay);
XFree(visualInfo); XFree(visualInfo);
XFreeColormap(mDisplay, colormap); XFreeColormap(mDisplay, colormap);
mGLXDisplay.syncXCommands(); mGLXDisplay->syncXCommands();
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
...@@ -140,6 +134,7 @@ egl::Error WindowSurfaceGLX::swap() ...@@ -140,6 +134,7 @@ egl::Error WindowSurfaceGLX::swap()
mGLX.waitX(); mGLX.waitX();
} }
mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
mGLX.swapBuffers(mGLXWindow); mGLX.swapBuffers(mGLXWindow);
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
...@@ -171,12 +166,7 @@ egl::Error WindowSurfaceGLX::releaseTexImage(EGLint buffer) ...@@ -171,12 +166,7 @@ egl::Error WindowSurfaceGLX::releaseTexImage(EGLint buffer)
void WindowSurfaceGLX::setSwapInterval(EGLint interval) void WindowSurfaceGLX::setSwapInterval(EGLint interval)
{ {
if (mGLX.hasExtension("GLX_EXT_swap_control")) mSwapControl.targetSwapInterval = interval;
{
// TODO(cwallez) error checking?
const int realInterval = std::min(interval, static_cast<int>(mMaxSwapInterval));
mGLX.swapIntervalEXT(mGLXWindow, realInterval);
}
} }
EGLint WindowSurfaceGLX::getWidth() const EGLint WindowSurfaceGLX::getWidth() const
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ #define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_
#include "libANGLE/renderer/gl/SurfaceGL.h" #include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/glx/DisplayGLX.h"
#include "libANGLE/renderer/gl/glx/platform_glx.h" #include "libANGLE/renderer/gl/glx/platform_glx.h"
namespace rx namespace rx
...@@ -55,12 +56,13 @@ class WindowSurfaceGLX : public SurfaceGL ...@@ -55,12 +56,13 @@ class WindowSurfaceGLX : public SurfaceGL
Display *mDisplay; Display *mDisplay;
const FunctionsGLX &mGLX; const FunctionsGLX &mGLX;
const DisplayGLX &mGLXDisplay; DisplayGLX *mGLXDisplay;
glx::Context mContext; glx::Context mContext;
glx::FBConfig mFBConfig; glx::FBConfig mFBConfig;
glx::Window mGLXWindow; 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