[declarative/core] Use proper GLXFBConfig for glxpixmap
We need to use a GLXFBConfig which matches the depth of the window pixmap's depth. So far it used the GLXFBConfig of the GL context. This worked fine for RGBA windows, but failed for RGB windows on e.g. some NVIDIA drivers. After this change the FBConfig of the context is completely ignored, instead it tries to find a good FBConfig for a given depth. Whenever a FBConfig for a given depth is found it's inserted in a cache shared between all WindowThumbnails so that we don't have the X roundtrips all the time. BUG: 334241 REVIEW: 118110
This commit is contained in:
parent
35d1dd2d65
commit
9653fad2f0
@ -65,6 +65,7 @@ WindowThumbnail::WindowThumbnail(QQuickItem *parent)
|
||||
, m_xcb(false)
|
||||
, m_winId(0)
|
||||
, m_damaged(false)
|
||||
, m_depth(0)
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
, m_openGLFunctionsResolved(false)
|
||||
, m_damageEventBase(0)
|
||||
@ -213,18 +214,18 @@ bool WindowThumbnail::windowToTextureGLX(WindowTextureNode *textureNode)
|
||||
if (m_glxPixmap == XCB_PIXMAP_NONE) {
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
auto geometryCookie = xcb_get_geometry_unchecked(c, m_pixmap);
|
||||
QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> geo(xcb_get_geometry_reply(c, geometryCookie, Q_NULLPTR));
|
||||
|
||||
if (geo.isNull()) {
|
||||
return false;
|
||||
}
|
||||
m_depth = geo->depth;
|
||||
|
||||
if (!loadGLXTexture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> geo(xcb_get_geometry_reply(c, geometryCookie, Q_NULLPTR));
|
||||
QSize size;
|
||||
if (!geo.isNull()) {
|
||||
size.setWidth(geo->width);
|
||||
size.setHeight(geo->height);
|
||||
}
|
||||
textureNode->reset(window()->createTextureFromId(m_texture, size, QQuickWindow::TextureOwnsGLTexture));
|
||||
textureNode->reset(window()->createTextureFromId(m_texture, QSize(geo->width, geo->height), QQuickWindow::TextureOwnsGLTexture));
|
||||
}
|
||||
textureNode->texture()->bind();
|
||||
bindGLXTexture();
|
||||
@ -390,47 +391,110 @@ void WindowThumbnail::bindGLXTexture()
|
||||
resetDamaged();
|
||||
}
|
||||
|
||||
GLXFBConfig *getConfig(int depth, int *index)
|
||||
{
|
||||
const int attribs[] = {
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PIXMAP_BIT,
|
||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||
GLX_X_RENDERABLE, 1,
|
||||
GLX_CONFIG_CAVEAT, int(GLX_DONT_CARE),
|
||||
GLX_RED_SIZE, 5,
|
||||
GLX_GREEN_SIZE, 5,
|
||||
GLX_BLUE_SIZE, 5,
|
||||
GLX_ALPHA_SIZE, 0,
|
||||
GLX_STENCIL_SIZE, 0,
|
||||
GLX_DEPTH_SIZE, 0, // note: this is depth buffer and has nothing to do with the X depth
|
||||
GLX_BIND_TO_TEXTURE_RGB_EXT, (depth == 32) ? int(GLX_DONT_CARE) : 1,
|
||||
GLX_BIND_TO_TEXTURE_RGBA_EXT, (depth == 32) ? 1 : int(GLX_DONT_CARE),
|
||||
0
|
||||
};
|
||||
|
||||
int count = 0;
|
||||
GLXFBConfig *fbConfigs = glXChooseFBConfig(QX11Info::display(), QX11Info::appScreen(), attribs, &count);
|
||||
if (count < 1) {
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
int alphaSize = 0;
|
||||
int bufferSize = 0;
|
||||
glXGetFBConfigAttrib(QX11Info::display(), fbConfigs[i], GLX_BUFFER_SIZE, &bufferSize);
|
||||
glXGetFBConfigAttrib(QX11Info::display(), fbConfigs[i], GLX_ALPHA_SIZE, &alphaSize);
|
||||
if (bufferSize != depth && (bufferSize - alphaSize) != depth) {
|
||||
continue;
|
||||
}
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig(QX11Info::display(), fbConfigs[i]);
|
||||
if (!vi) {
|
||||
// no visual for the fb config - skip
|
||||
continue;
|
||||
}
|
||||
const int visualDepth = vi->depth;
|
||||
XFree(vi);
|
||||
|
||||
if (visualDepth != depth) {
|
||||
// depth of the visual doesn't match our wanted depth - skip
|
||||
continue;
|
||||
}
|
||||
*index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return fbConfigs;
|
||||
}
|
||||
|
||||
bool WindowThumbnail::loadGLXTexture()
|
||||
{
|
||||
GLXContext glxContext = glXGetCurrentContext();
|
||||
if (!glxContext) {
|
||||
return false;
|
||||
}
|
||||
Display *d = QX11Info::display();
|
||||
|
||||
// this is a cache of the GLXFBConfig per depth
|
||||
// it's kept as a method static to have it shared between multiple
|
||||
// window thumbnails.
|
||||
// As the GLXFBConfig might be context specific and we cannot be sure
|
||||
// that the code might be entered from different contexts, the cache
|
||||
// also maps the cached configs against the context.
|
||||
static QMap<GLXContext, QMap<int, GLXFBConfig> > s_fbConfigs;
|
||||
auto it = s_fbConfigs.find(glxContext);
|
||||
if (it == s_fbConfigs.end()) {
|
||||
// create a map entry for the current context
|
||||
s_fbConfigs.insert(glxContext, QMap<int, GLXFBConfig>());
|
||||
it = s_fbConfigs.find(glxContext);
|
||||
if (it == s_fbConfigs.end()) {
|
||||
// just for safety, should never ever happen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
auto &configMap = it.value();
|
||||
auto configIt = configMap.constFind(m_depth);
|
||||
if (configIt == configMap.constEnd()) {
|
||||
// try getting a new fbconfig for the current depth
|
||||
int index = 0;
|
||||
GLXFBConfig *fbConfigs = getConfig(m_depth, &index);
|
||||
if (!fbConfigs) {
|
||||
return false;
|
||||
}
|
||||
configMap.insert(m_depth, fbConfigs[index]);
|
||||
XFree(fbConfigs);
|
||||
|
||||
configIt = configMap.constFind(m_depth);
|
||||
if (configIt == configMap.constEnd()) {
|
||||
// just for safety, should never ever happen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
glGenTextures(1, &m_texture);
|
||||
int fbConfig = 0;
|
||||
glXQueryContext(d, glxContext, GLX_FBCONFIG_ID, &fbConfig);
|
||||
|
||||
int fbAttribs[] = {
|
||||
GLX_FBCONFIG_ID, fbConfig, XCB_NONE
|
||||
};
|
||||
int count = 0;
|
||||
GLXFBConfig *fbConfigs = glXChooseFBConfig(d, QX11Info::appScreen(), fbAttribs, &count);
|
||||
if (count == 0) {
|
||||
qDebug() << "Didn't get our FBConfig";
|
||||
return false;
|
||||
}
|
||||
|
||||
int bindRgb, bindRgba;
|
||||
glXGetFBConfigAttrib(d, fbConfigs[0], GLX_BIND_TO_TEXTURE_RGBA_EXT, &bindRgba);
|
||||
glXGetFBConfigAttrib(d, fbConfigs[0], GLX_BIND_TO_TEXTURE_RGB_EXT, &bindRgb);
|
||||
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig(d, fbConfigs[0]);
|
||||
int textureFormat;
|
||||
if (window()->openglContext()->format().hasAlpha()) {
|
||||
textureFormat = bindRgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
|
||||
} else {
|
||||
textureFormat = bindRgb ? GLX_TEXTURE_FORMAT_RGB_EXT : GLX_TEXTURE_FORMAT_RGBA_EXT;
|
||||
}
|
||||
XFree(vi);
|
||||
|
||||
// we assume that Texture_2D is supported as we have a QtQuick OpenGL context
|
||||
int attrs[] = {
|
||||
GLX_TEXTURE_FORMAT_EXT, textureFormat,
|
||||
GLX_TEXTURE_FORMAT_EXT, (m_depth == 32) ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
|
||||
GLX_MIPMAP_TEXTURE_EXT, false,
|
||||
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, XCB_NONE
|
||||
};
|
||||
m_glxPixmap = glXCreatePixmap(d, fbConfigs[0], m_pixmap, attrs);
|
||||
m_glxPixmap = glXCreatePixmap(QX11Info::display(), configIt.value(), m_pixmap, attrs);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -95,6 +95,7 @@ private:
|
||||
bool m_xcb;
|
||||
uint32_t m_winId;
|
||||
bool m_damaged;
|
||||
int m_depth;
|
||||
#if HAVE_XCB_COMPOSITE
|
||||
xcb_pixmap_t pixmapForWindow();
|
||||
bool m_openGLFunctionsResolved;
|
||||
|
Loading…
Reference in New Issue
Block a user