texture-pixmap-x11: Move GLX code to cogl-winsys-glx.c
This moves the GLX specific code from cogl-texture-pixmap-x11.c into cogl-winsys-glx.c. If we want the winsys components to by dynamically loadable then we can't have GLX code scattered outside of cogl-winsys-glx.c. This also sets us up for supporting the EGL_texture_from_pixmap extension which is almost identical to the GLX_texture_from_pixmap extension.
This commit is contained in:
parent
d5d11f1878
commit
d52e3f0cc2
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "cogl-handle.h"
|
#include "cogl-handle.h"
|
||||||
#include "cogl-texture-private.h"
|
#include "cogl-texture-private.h"
|
||||||
|
#include "cogl-texture-pixmap-x11.h"
|
||||||
|
|
||||||
#define COGL_TEXTURE_PIXMAP_X11(tex) ((CoglTexturePixmapX11 *) tex)
|
#define COGL_TEXTURE_PIXMAP_X11(tex) ((CoglTexturePixmapX11 *) tex)
|
||||||
|
|
||||||
@ -72,18 +73,12 @@ struct _CoglTexturePixmapX11
|
|||||||
gboolean damage_owned;
|
gboolean damage_owned;
|
||||||
CoglDamageRectangle damage_rect;
|
CoglDamageRectangle damage_rect;
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
void *winsys;
|
||||||
|
|
||||||
/* During the pre_paint method, this will be set to TRUE if we
|
/* During the pre_paint method, this will be set to TRUE if we
|
||||||
should use the GLX texture, otherwise we will use the regular
|
should use the winsys texture, otherwise we will use the regular
|
||||||
texture */
|
texture */
|
||||||
gboolean use_glx_texture;
|
gboolean use_winsys_texture;
|
||||||
CoglHandle glx_tex;
|
|
||||||
GLXPixmap glx_pixmap;
|
|
||||||
gboolean glx_pixmap_has_mipmap;
|
|
||||||
gboolean glx_can_mipmap;
|
|
||||||
gboolean bind_tex_image_queued;
|
|
||||||
gboolean pixmap_bound;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GQuark
|
GQuark
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* Authors:
|
* Authors:
|
||||||
* Neil Roberts <neil@linux.intel.com>
|
* Neil Roberts <neil@linux.intel.com>
|
||||||
* Johan Bilien <johan.bilien@nokia.com>
|
* Johan Bilien <johan.bilien@nokia.com>
|
||||||
|
* Robert Bragg <robert@linux.intel.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@ -42,11 +43,7 @@
|
|||||||
#include "cogl-texture-rectangle-private.h"
|
#include "cogl-texture-rectangle-private.h"
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
#include "cogl-handle.h"
|
#include "cogl-handle.h"
|
||||||
#if COGL_HAS_GLX_SUPPORT
|
#include "cogl-winsys-private.h"
|
||||||
#include "cogl-display-glx-private.h"
|
|
||||||
#include "cogl-renderer-private.h"
|
|
||||||
#include "cogl-renderer-glx-private.h"
|
|
||||||
#endif
|
|
||||||
#include "cogl-pipeline-opengl-private.h"
|
#include "cogl-pipeline-opengl-private.h"
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
@ -198,9 +195,7 @@ process_damage_event (CoglTexturePixmapX11 *tex_pixmap,
|
|||||||
/* If we're using the texture from pixmap extension then there's no
|
/* If we're using the texture from pixmap extension then there's no
|
||||||
point in getting the region and we can just mark that the texture
|
point in getting the region and we can just mark that the texture
|
||||||
needs updating */
|
needs updating */
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
_cogl_winsys_texture_pixmap_x11_damage_notify (tex_pixmap);
|
||||||
tex_pixmap->bind_tex_image_queued = TRUE;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CoglFilterReturn
|
static CoglFilterReturn
|
||||||
@ -224,283 +219,6 @@ _cogl_texture_pixmap_x11_filter (void *native_event, void *data)
|
|||||||
return COGL_FILTER_CONTINUE;
|
return COGL_FILTER_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
get_fbconfig_for_depth (unsigned int depth,
|
|
||||||
GLXFBConfig *fbconfig_ret,
|
|
||||||
gboolean *can_mipmap_ret)
|
|
||||||
{
|
|
||||||
GLXFBConfig *fbconfigs;
|
|
||||||
int n_elements, i;
|
|
||||||
Display *dpy;
|
|
||||||
int db, stencil, alpha, mipmap, rgba, value;
|
|
||||||
int spare_cache_slot = 0;
|
|
||||||
gboolean found = FALSE;
|
|
||||||
CoglDisplayGLX *glx_display;
|
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctxt, FALSE);
|
|
||||||
glx_display = ctxt->display->winsys;
|
|
||||||
|
|
||||||
/* Check if we've already got a cached config for this depth */
|
|
||||||
for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++)
|
|
||||||
if (glx_display->glx_cached_configs[i].depth == -1)
|
|
||||||
spare_cache_slot = i;
|
|
||||||
else if (glx_display->glx_cached_configs[i].depth == depth)
|
|
||||||
{
|
|
||||||
*fbconfig_ret = glx_display->glx_cached_configs[i].fb_config;
|
|
||||||
*can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap;
|
|
||||||
return glx_display->glx_cached_configs[i].found;
|
|
||||||
}
|
|
||||||
|
|
||||||
dpy = cogl_xlib_get_display ();
|
|
||||||
|
|
||||||
fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy),
|
|
||||||
&n_elements);
|
|
||||||
|
|
||||||
db = G_MAXSHORT;
|
|
||||||
stencil = G_MAXSHORT;
|
|
||||||
mipmap = 0;
|
|
||||||
rgba = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < n_elements; i++)
|
|
||||||
{
|
|
||||||
XVisualInfo *vi;
|
|
||||||
int visual_depth;
|
|
||||||
|
|
||||||
vi = glXGetVisualFromFBConfig (dpy,
|
|
||||||
fbconfigs[i]);
|
|
||||||
if (vi == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
visual_depth = vi->depth;
|
|
||||||
|
|
||||||
XFree (vi);
|
|
||||||
|
|
||||||
if (visual_depth != depth)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_ALPHA_SIZE,
|
|
||||||
&alpha);
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_BUFFER_SIZE,
|
|
||||||
&value);
|
|
||||||
if (value != depth && (value - alpha) != depth)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
value = 0;
|
|
||||||
if (depth == 32)
|
|
||||||
{
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_BIND_TO_TEXTURE_RGBA_EXT,
|
|
||||||
&value);
|
|
||||||
if (value)
|
|
||||||
rgba = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value)
|
|
||||||
{
|
|
||||||
if (rgba)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_BIND_TO_TEXTURE_RGB_EXT,
|
|
||||||
&value);
|
|
||||||
if (!value)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_DOUBLEBUFFER,
|
|
||||||
&value);
|
|
||||||
if (value > db)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
db = value;
|
|
||||||
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_STENCIL_SIZE,
|
|
||||||
&value);
|
|
||||||
if (value > stencil)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
stencil = value;
|
|
||||||
|
|
||||||
/* glGenerateMipmap is defined in the offscreen extension */
|
|
||||||
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
|
|
||||||
{
|
|
||||||
glXGetFBConfigAttrib (dpy,
|
|
||||||
fbconfigs[i],
|
|
||||||
GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
|
|
||||||
&value);
|
|
||||||
|
|
||||||
if (value < mipmap)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
mipmap = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
*fbconfig_ret = fbconfigs[i];
|
|
||||||
*can_mipmap_ret = mipmap;
|
|
||||||
found = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_elements)
|
|
||||||
XFree (fbconfigs);
|
|
||||||
|
|
||||||
glx_display->glx_cached_configs[spare_cache_slot].depth = depth;
|
|
||||||
glx_display->glx_cached_configs[spare_cache_slot].found = found;
|
|
||||||
glx_display->glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret;
|
|
||||||
glx_display->glx_cached_configs[spare_cache_slot].can_mipmap = mipmap;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
should_use_rectangle (void)
|
|
||||||
{
|
|
||||||
_COGL_GET_CONTEXT (ctxt, FALSE);
|
|
||||||
|
|
||||||
if (ctxt->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN)
|
|
||||||
{
|
|
||||||
if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE))
|
|
||||||
{
|
|
||||||
const char *rect_env;
|
|
||||||
|
|
||||||
/* Use the rectangle only if it is available and either:
|
|
||||||
|
|
||||||
the COGL_PIXMAP_TEXTURE_RECTANGLE environment variable is
|
|
||||||
set to 'force'
|
|
||||||
|
|
||||||
*or*
|
|
||||||
|
|
||||||
the env var is set to 'allow' or not set and NPOTs textures
|
|
||||||
are not available */
|
|
||||||
|
|
||||||
ctxt->rectangle_state =
|
|
||||||
cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ?
|
|
||||||
COGL_WINSYS_RECTANGLE_STATE_DISABLE :
|
|
||||||
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
|
||||||
|
|
||||||
if ((rect_env = g_getenv ("COGL_PIXMAP_TEXTURE_RECTANGLE")) ||
|
|
||||||
/* For compatibility, we'll also look at the old Clutter
|
|
||||||
environment variable */
|
|
||||||
(rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
|
|
||||||
{
|
|
||||||
if (g_ascii_strcasecmp (rect_env, "force") == 0)
|
|
||||||
ctxt->rectangle_state =
|
|
||||||
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
|
||||||
else if (g_ascii_strcasecmp (rect_env, "disable") == 0)
|
|
||||||
ctxt->rectangle_state =
|
|
||||||
COGL_WINSYS_RECTANGLE_STATE_DISABLE;
|
|
||||||
else if (g_ascii_strcasecmp (rect_env, "allow"))
|
|
||||||
g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, "
|
|
||||||
"should be 'force' or 'disable'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ctxt->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctxt->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
try_create_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap,
|
|
||||||
gboolean mipmap)
|
|
||||||
{
|
|
||||||
Display *dpy;
|
|
||||||
/* We have to initialize this *opaque* variable because gcc tries to
|
|
||||||
* be too smart for its own good and warns that the variable may be
|
|
||||||
* used uninitialized otherwise. */
|
|
||||||
GLXFBConfig fb_config = (GLXFBConfig)0;
|
|
||||||
int attribs[7];
|
|
||||||
int i = 0;
|
|
||||||
GLenum target;
|
|
||||||
CoglXlibTrapState trap_state;
|
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctxt, NO_RETVAL);
|
|
||||||
|
|
||||||
tex_pixmap->pixmap_bound = FALSE;
|
|
||||||
tex_pixmap->glx_pixmap = None;
|
|
||||||
|
|
||||||
if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP))
|
|
||||||
return;
|
|
||||||
|
|
||||||
dpy = cogl_xlib_get_display ();
|
|
||||||
|
|
||||||
if (!get_fbconfig_for_depth (tex_pixmap->depth, &fb_config,
|
|
||||||
&tex_pixmap->glx_can_mipmap))
|
|
||||||
{
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "No suitable FBConfig found for depth %i",
|
|
||||||
tex_pixmap->depth);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_use_rectangle ())
|
|
||||||
{
|
|
||||||
target = GLX_TEXTURE_RECTANGLE_EXT;
|
|
||||||
tex_pixmap->glx_can_mipmap = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
target = GLX_TEXTURE_2D_EXT;
|
|
||||||
|
|
||||||
if (!tex_pixmap->glx_can_mipmap)
|
|
||||||
mipmap = FALSE;
|
|
||||||
|
|
||||||
attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
|
|
||||||
|
|
||||||
if (tex_pixmap->depth == 24)
|
|
||||||
attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
|
|
||||||
else if (tex_pixmap->depth == 32)
|
|
||||||
attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
|
|
||||||
attribs[i++] = mipmap;
|
|
||||||
|
|
||||||
attribs[i++] = GLX_TEXTURE_TARGET_EXT;
|
|
||||||
attribs[i++] = target;
|
|
||||||
|
|
||||||
attribs[i++] = None;
|
|
||||||
|
|
||||||
/* We need to trap errors from glXCreatePixmap because it can
|
|
||||||
sometimes fail during normal usage. For example on NVidia it gets
|
|
||||||
upset if you try to create two GLXPixmaps for the same
|
|
||||||
drawable. */
|
|
||||||
|
|
||||||
_cogl_xlib_trap_errors (&trap_state);
|
|
||||||
|
|
||||||
tex_pixmap->glx_pixmap = glXCreatePixmap (dpy,
|
|
||||||
fb_config,
|
|
||||||
tex_pixmap->pixmap,
|
|
||||||
attribs);
|
|
||||||
tex_pixmap->glx_pixmap_has_mipmap = mipmap;
|
|
||||||
|
|
||||||
XSync (dpy, False);
|
|
||||||
|
|
||||||
if (_cogl_xlib_untrap_errors (&trap_state))
|
|
||||||
{
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Failed to create pixmap for %p", tex_pixmap);
|
|
||||||
_cogl_xlib_trap_errors (&trap_state);
|
|
||||||
glXDestroyPixmap (dpy, tex_pixmap->glx_pixmap);
|
|
||||||
XSync (dpy, False);
|
|
||||||
_cogl_xlib_untrap_errors (&trap_state);
|
|
||||||
|
|
||||||
tex_pixmap->glx_pixmap = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* COGL_HAS_GLX_SUPPORT */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_damage_object_internal (CoglTexturePixmapX11 *tex_pixmap,
|
set_damage_object_internal (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
Damage damage,
|
Damage damage,
|
||||||
@ -589,13 +307,7 @@ cogl_texture_pixmap_x11_new (guint32 pixmap,
|
|||||||
tex_pixmap->damage_rect.y1 = 0;
|
tex_pixmap->damage_rect.y1 = 0;
|
||||||
tex_pixmap->damage_rect.y2 = tex_pixmap->height;
|
tex_pixmap->damage_rect.y2 = tex_pixmap->height;
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
_cogl_winsys_texture_pixmap_x11_create (tex_pixmap);
|
||||||
try_create_glx_pixmap (tex_pixmap, FALSE);
|
|
||||||
|
|
||||||
tex_pixmap->glx_tex = COGL_INVALID_HANDLE;
|
|
||||||
tex_pixmap->bind_tex_image_queued = TRUE;
|
|
||||||
tex_pixmap->use_glx_texture = FALSE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return _cogl_texture_pixmap_x11_handle_new (tex_pixmap);
|
return _cogl_texture_pixmap_x11_handle_new (tex_pixmap);
|
||||||
}
|
}
|
||||||
@ -686,9 +398,7 @@ cogl_texture_pixmap_x11_update_area (CoglHandle handle,
|
|||||||
texture because we can't determine which will be needed until we
|
texture because we can't determine which will be needed until we
|
||||||
actually render something */
|
actually render something */
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
_cogl_winsys_texture_pixmap_x11_damage_notify (tex_pixmap);
|
||||||
tex_pixmap->bind_tex_image_queued = TRUE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cogl_damage_rectangle_union (&tex_pixmap->damage_rect,
|
cogl_damage_rectangle_union (&tex_pixmap->damage_rect,
|
||||||
x, y, width, height);
|
x, y, width, height);
|
||||||
@ -702,11 +412,7 @@ cogl_texture_pixmap_x11_is_using_tfp_extension (CoglHandle handle)
|
|||||||
if (!cogl_is_texture_pixmap_x11 (tex_pixmap))
|
if (!cogl_is_texture_pixmap_x11 (tex_pixmap))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
return !!tex_pixmap->winsys;
|
||||||
return tex_pixmap->glx_pixmap != None;
|
|
||||||
#else
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -890,225 +596,37 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
|
|||||||
memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle));
|
memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_cogl_texture_pixmap_x11_free_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap)
|
_cogl_texture_pixmap_x11_set_use_winsys_texture (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
{
|
|
||||||
if (tex_pixmap->glx_pixmap)
|
|
||||||
{
|
|
||||||
CoglXlibTrapState trap_state;
|
|
||||||
CoglRendererGLX *glx_renderer;
|
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
||||||
glx_renderer = ctx->display->renderer->winsys;
|
|
||||||
|
|
||||||
if (tex_pixmap->pixmap_bound)
|
|
||||||
glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
|
|
||||||
tex_pixmap->glx_pixmap,
|
|
||||||
GLX_FRONT_LEFT_EXT);
|
|
||||||
|
|
||||||
/* FIXME - we need to trap errors and synchronize here because
|
|
||||||
* of ordering issues between the XPixmap destruction and the
|
|
||||||
* GLXPixmap destruction.
|
|
||||||
*
|
|
||||||
* If the X pixmap is destroyed, the GLX pixmap is destroyed as
|
|
||||||
* well immediately, and thus, when Cogl calls glXDestroyPixmap()
|
|
||||||
* it'll cause a BadDrawable error.
|
|
||||||
*
|
|
||||||
* this is technically a bug in the X server, which should not
|
|
||||||
* destroy either pixmaps until the call to glXDestroyPixmap(); so
|
|
||||||
* at some point we should revisit this code and remove the
|
|
||||||
* trap+sync after verifying that the destruction is indeed safe.
|
|
||||||
*
|
|
||||||
* for reference, see:
|
|
||||||
* http://bugzilla.clutter-project.org/show_bug.cgi?id=2324
|
|
||||||
*/
|
|
||||||
_cogl_xlib_trap_errors (&trap_state);
|
|
||||||
glXDestroyPixmap (cogl_xlib_get_display (), tex_pixmap->glx_pixmap);
|
|
||||||
XSync (cogl_xlib_get_display (), False);
|
|
||||||
_cogl_xlib_untrap_errors (&trap_state);
|
|
||||||
|
|
||||||
tex_pixmap->glx_pixmap = None;
|
|
||||||
tex_pixmap->pixmap_bound = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
|
|
||||||
gboolean needs_mipmap)
|
|
||||||
{
|
|
||||||
gboolean ret = TRUE;
|
|
||||||
CoglRendererGLX *glx_renderer;
|
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
|
||||||
glx_renderer = ctx->display->renderer->winsys;
|
|
||||||
|
|
||||||
/* If we don't have a GLX pixmap then fallback */
|
|
||||||
if (tex_pixmap->glx_pixmap == None)
|
|
||||||
ret = FALSE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Lazily create a texture to hold the pixmap */
|
|
||||||
if (tex_pixmap->glx_tex == COGL_INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
CoglPixelFormat texture_format;
|
|
||||||
|
|
||||||
texture_format = (tex_pixmap->depth >= 32 ?
|
|
||||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE :
|
|
||||||
COGL_PIXEL_FORMAT_RGB_888);
|
|
||||||
|
|
||||||
if (should_use_rectangle ())
|
|
||||||
{
|
|
||||||
tex_pixmap->glx_tex =
|
|
||||||
_cogl_texture_rectangle_new_with_size (tex_pixmap->width,
|
|
||||||
tex_pixmap->height,
|
|
||||||
COGL_TEXTURE_NO_ATLAS,
|
|
||||||
texture_format);
|
|
||||||
|
|
||||||
if (tex_pixmap->glx_tex)
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p",
|
|
||||||
tex_pixmap);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
|
|
||||||
"texture rectangle could not be created",
|
|
||||||
tex_pixmap);
|
|
||||||
_cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tex_pixmap->glx_tex =
|
|
||||||
_cogl_texture_2d_new_with_size (tex_pixmap->width,
|
|
||||||
tex_pixmap->height,
|
|
||||||
COGL_TEXTURE_NO_ATLAS,
|
|
||||||
texture_format);
|
|
||||||
|
|
||||||
if (tex_pixmap->glx_tex)
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p",
|
|
||||||
tex_pixmap);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
|
|
||||||
"texture 2d could not be created",
|
|
||||||
tex_pixmap);
|
|
||||||
_cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret && needs_mipmap)
|
|
||||||
{
|
|
||||||
/* If we can't support mipmapping then temporarily fallback */
|
|
||||||
if (!tex_pixmap->glx_can_mipmap)
|
|
||||||
ret = FALSE;
|
|
||||||
/* Recreate the GLXPixmap if it wasn't previously created with a
|
|
||||||
mipmap tree */
|
|
||||||
else if (!tex_pixmap->glx_pixmap_has_mipmap)
|
|
||||||
{
|
|
||||||
_cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
|
|
||||||
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Recreating GLXPixmap with mipmap "
|
|
||||||
"support for %p", tex_pixmap);
|
|
||||||
try_create_glx_pixmap (tex_pixmap, TRUE);
|
|
||||||
|
|
||||||
/* If the pixmap failed then we'll permanently fallback to using
|
|
||||||
XImage. This shouldn't happen */
|
|
||||||
if (tex_pixmap->glx_pixmap == None)
|
|
||||||
{
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Falling back to XGetImage "
|
|
||||||
"updates for %p because creating the GLXPixmap "
|
|
||||||
"with mipmap support failed", tex_pixmap);
|
|
||||||
|
|
||||||
if (tex_pixmap->glx_tex)
|
|
||||||
cogl_handle_unref (tex_pixmap->glx_tex);
|
|
||||||
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tex_pixmap->bind_tex_image_queued = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret && tex_pixmap->bind_tex_image_queued)
|
|
||||||
{
|
|
||||||
GLuint gl_handle, gl_target;
|
|
||||||
|
|
||||||
cogl_texture_get_gl_texture (tex_pixmap->glx_tex,
|
|
||||||
&gl_handle, &gl_target);
|
|
||||||
|
|
||||||
COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap);
|
|
||||||
|
|
||||||
GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) );
|
|
||||||
|
|
||||||
if (tex_pixmap->pixmap_bound)
|
|
||||||
glx_renderer->pf_glXReleaseTexImage (cogl_xlib_get_display (),
|
|
||||||
tex_pixmap->glx_pixmap,
|
|
||||||
GLX_FRONT_LEFT_EXT);
|
|
||||||
|
|
||||||
glx_renderer->pf_glXBindTexImage (cogl_xlib_get_display (),
|
|
||||||
tex_pixmap->glx_pixmap,
|
|
||||||
GLX_FRONT_LEFT_EXT,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* According to the recommended usage in the spec for
|
|
||||||
GLX_EXT_texture_pixmap we should release the texture after
|
|
||||||
we've finished drawing with it and it is undefined what
|
|
||||||
happens if you render to a pixmap that is bound to a
|
|
||||||
texture. However that would require the texture backend to
|
|
||||||
know when Cogl has finished painting and it may be more
|
|
||||||
expensive to keep unbinding the texture. Leaving it bound
|
|
||||||
appears to work on Mesa and NVidia drivers and it is also
|
|
||||||
what Compiz does so it is probably ok */
|
|
||||||
|
|
||||||
tex_pixmap->bind_tex_image_queued = FALSE;
|
|
||||||
tex_pixmap->pixmap_bound = TRUE;
|
|
||||||
|
|
||||||
_cogl_texture_2d_externally_modified (tex_pixmap->glx_tex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_cogl_texture_pixmap_x11_set_use_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
|
|
||||||
gboolean new_value)
|
gboolean new_value)
|
||||||
{
|
{
|
||||||
if (tex_pixmap->use_glx_texture != new_value)
|
if (tex_pixmap->use_winsys_texture != new_value)
|
||||||
{
|
{
|
||||||
/* Notify cogl-pipeline.c that the texture's underlying GL texture
|
/* Notify cogl-pipeline.c that the texture's underlying GL texture
|
||||||
* storage is changing so it knows it may need to bind a new texture
|
* storage is changing so it knows it may need to bind a new texture
|
||||||
* if the CoglTexture is reused with the same texture unit. */
|
* if the CoglTexture is reused with the same texture unit. */
|
||||||
_cogl_pipeline_texture_storage_change_notify (tex_pixmap);
|
_cogl_pipeline_texture_storage_change_notify (tex_pixmap);
|
||||||
|
|
||||||
tex_pixmap->use_glx_texture = new_value;
|
tex_pixmap->use_winsys_texture = new_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* COGL_HAS_GLX_SUPPORT */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_cogl_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
|
_cogl_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
gboolean needs_mipmap)
|
gboolean needs_mipmap)
|
||||||
{
|
{
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
if (tex_pixmap->winsys)
|
||||||
|
|
||||||
/* First try updating with GLX TFP */
|
|
||||||
if (_cogl_texture_pixmap_x11_update_glx_texture (tex_pixmap, needs_mipmap))
|
|
||||||
{
|
{
|
||||||
_cogl_texture_pixmap_x11_set_use_glx_texture (tex_pixmap, TRUE);
|
if (_cogl_winsys_texture_pixmap_x11_update (tex_pixmap, needs_mipmap))
|
||||||
|
{
|
||||||
|
_cogl_texture_pixmap_x11_set_use_winsys_texture (tex_pixmap, TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If it didn't work then fallback to using XGetImage. This may be
|
/* If it didn't work then fallback to using XGetImage. This may be
|
||||||
temporary */
|
temporary */
|
||||||
_cogl_texture_pixmap_x11_set_use_glx_texture (tex_pixmap, FALSE);
|
_cogl_texture_pixmap_x11_set_use_winsys_texture (tex_pixmap, FALSE);
|
||||||
|
|
||||||
#endif /* COGL_HAS_GLX_SUPPORT */
|
|
||||||
|
|
||||||
_cogl_texture_pixmap_x11_update_image_texture (tex_pixmap);
|
_cogl_texture_pixmap_x11_update_image_texture (tex_pixmap);
|
||||||
}
|
}
|
||||||
@ -1130,11 +648,9 @@ _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap)
|
|||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
if (tex_pixmap->use_winsys_texture)
|
||||||
if (tex_pixmap->use_glx_texture)
|
tex = _cogl_winsys_texture_pixmap_x11_get_texture (tex_pixmap);
|
||||||
tex = tex_pixmap->glx_tex;
|
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
tex = tex_pixmap->tex;
|
tex = tex_pixmap->tex;
|
||||||
|
|
||||||
if (tex)
|
if (tex)
|
||||||
@ -1395,12 +911,8 @@ _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap)
|
|||||||
if (tex_pixmap->tex)
|
if (tex_pixmap->tex)
|
||||||
cogl_handle_unref (tex_pixmap->tex);
|
cogl_handle_unref (tex_pixmap->tex);
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLX_SUPPORT
|
if (tex_pixmap->winsys)
|
||||||
_cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
|
_cogl_winsys_texture_pixmap_x11_free (tex_pixmap);
|
||||||
|
|
||||||
if (tex_pixmap->glx_tex)
|
|
||||||
cogl_handle_unref (tex_pixmap->glx_tex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Chain up */
|
/* Chain up */
|
||||||
_cogl_texture_free (COGL_TEXTURE (tex_pixmap));
|
_cogl_texture_free (COGL_TEXTURE (tex_pixmap));
|
||||||
|
@ -1079,3 +1079,38 @@ _cogl_winsys_context_egl_get_egl_display (CoglContext *context)
|
|||||||
|
|
||||||
return egl_renderer->edpy;
|
return egl_renderer->edpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
/* Unsupported feature */
|
||||||
|
tex_pixmap->winsys = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
/* Unsupported feature */
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
|
gboolean needs_mipmap)
|
||||||
|
{
|
||||||
|
/* Unsupported feature */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
/* Unsupported feature */
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglHandle
|
||||||
|
_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
/* Unsupported feature */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
#include "cogl-display-xlib-private.h"
|
#include "cogl-display-xlib-private.h"
|
||||||
#include "cogl-display-glx-private.h"
|
#include "cogl-display-glx-private.h"
|
||||||
#include "cogl-private.h"
|
#include "cogl-private.h"
|
||||||
|
#include "cogl-texture-2d-private.h"
|
||||||
|
#include "cogl-texture-rectangle-private.h"
|
||||||
|
#include "cogl-pipeline-opengl-private.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -87,6 +90,17 @@ typedef struct _CoglSwapBuffersNotifyEntry
|
|||||||
unsigned int id;
|
unsigned int id;
|
||||||
} CoglSwapBuffersNotifyEntry;
|
} CoglSwapBuffersNotifyEntry;
|
||||||
|
|
||||||
|
typedef struct _CoglTexturePixmapGLX
|
||||||
|
{
|
||||||
|
GLXPixmap glx_pixmap;
|
||||||
|
gboolean has_mipmap_space;
|
||||||
|
gboolean can_mipmap;
|
||||||
|
|
||||||
|
CoglHandle glx_tex;
|
||||||
|
|
||||||
|
gboolean bind_tex_image_queued;
|
||||||
|
gboolean pixmap_bound;
|
||||||
|
} CoglTexturePixmapGLX;
|
||||||
|
|
||||||
/* Define a set of arrays containing the functions required from GL
|
/* Define a set of arrays containing the functions required from GL
|
||||||
for each winsys feature */
|
for each winsys feature */
|
||||||
@ -1327,3 +1341,538 @@ _cogl_winsys_xlib_get_visual_info (void)
|
|||||||
|
|
||||||
return glXGetVisualFromFBConfig (xlib_renderer->xdpy, glx_display->fbconfig);
|
return glXGetVisualFromFBConfig (xlib_renderer->xdpy, glx_display->fbconfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_fbconfig_for_depth (CoglContext *context,
|
||||||
|
unsigned int depth,
|
||||||
|
GLXFBConfig *fbconfig_ret,
|
||||||
|
gboolean *can_mipmap_ret)
|
||||||
|
{
|
||||||
|
CoglRendererXlib *xlib_renderer;
|
||||||
|
CoglDisplayGLX *glx_display;
|
||||||
|
Display *dpy;
|
||||||
|
GLXFBConfig *fbconfigs;
|
||||||
|
int n_elements, i;
|
||||||
|
int db, stencil, alpha, mipmap, rgba, value;
|
||||||
|
int spare_cache_slot = 0;
|
||||||
|
gboolean found = FALSE;
|
||||||
|
|
||||||
|
xlib_renderer = context->display->renderer->winsys;
|
||||||
|
glx_display = context->display->winsys;
|
||||||
|
|
||||||
|
/* Check if we've already got a cached config for this depth */
|
||||||
|
for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++)
|
||||||
|
if (glx_display->glx_cached_configs[i].depth == -1)
|
||||||
|
spare_cache_slot = i;
|
||||||
|
else if (glx_display->glx_cached_configs[i].depth == depth)
|
||||||
|
{
|
||||||
|
*fbconfig_ret = glx_display->glx_cached_configs[i].fb_config;
|
||||||
|
*can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap;
|
||||||
|
return glx_display->glx_cached_configs[i].found;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpy = xlib_renderer->xdpy;
|
||||||
|
|
||||||
|
fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy), &n_elements);
|
||||||
|
|
||||||
|
db = G_MAXSHORT;
|
||||||
|
stencil = G_MAXSHORT;
|
||||||
|
mipmap = 0;
|
||||||
|
rgba = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < n_elements; i++)
|
||||||
|
{
|
||||||
|
XVisualInfo *vi;
|
||||||
|
int visual_depth;
|
||||||
|
|
||||||
|
vi = glXGetVisualFromFBConfig (dpy, fbconfigs[i]);
|
||||||
|
if (vi == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
visual_depth = vi->depth;
|
||||||
|
|
||||||
|
XFree (vi);
|
||||||
|
|
||||||
|
if (visual_depth != depth)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_ALPHA_SIZE,
|
||||||
|
&alpha);
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_BUFFER_SIZE,
|
||||||
|
&value);
|
||||||
|
if (value != depth && (value - alpha) != depth)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
value = 0;
|
||||||
|
if (depth == 32)
|
||||||
|
{
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_BIND_TO_TEXTURE_RGBA_EXT,
|
||||||
|
&value);
|
||||||
|
if (value)
|
||||||
|
rgba = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
if (rgba)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_BIND_TO_TEXTURE_RGB_EXT,
|
||||||
|
&value);
|
||||||
|
if (!value)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_DOUBLEBUFFER,
|
||||||
|
&value);
|
||||||
|
if (value > db)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
db = value;
|
||||||
|
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_STENCIL_SIZE,
|
||||||
|
&value);
|
||||||
|
if (value > stencil)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stencil = value;
|
||||||
|
|
||||||
|
/* glGenerateMipmap is defined in the offscreen extension */
|
||||||
|
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
|
||||||
|
{
|
||||||
|
glXGetFBConfigAttrib (dpy,
|
||||||
|
fbconfigs[i],
|
||||||
|
GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
|
||||||
|
&value);
|
||||||
|
|
||||||
|
if (value < mipmap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mipmap = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fbconfig_ret = fbconfigs[i];
|
||||||
|
*can_mipmap_ret = mipmap;
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_elements)
|
||||||
|
XFree (fbconfigs);
|
||||||
|
|
||||||
|
glx_display->glx_cached_configs[spare_cache_slot].depth = depth;
|
||||||
|
glx_display->glx_cached_configs[spare_cache_slot].found = found;
|
||||||
|
glx_display->glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret;
|
||||||
|
glx_display->glx_cached_configs[spare_cache_slot].can_mipmap = mipmap;
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
should_use_rectangle (CoglContext *context)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN)
|
||||||
|
{
|
||||||
|
if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE))
|
||||||
|
{
|
||||||
|
const char *rect_env;
|
||||||
|
|
||||||
|
/* Use the rectangle only if it is available and either:
|
||||||
|
|
||||||
|
the COGL_PIXMAP_TEXTURE_RECTANGLE environment variable is
|
||||||
|
set to 'force'
|
||||||
|
|
||||||
|
*or*
|
||||||
|
|
||||||
|
the env var is set to 'allow' or not set and NPOTs textures
|
||||||
|
are not available */
|
||||||
|
|
||||||
|
context->rectangle_state =
|
||||||
|
cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ?
|
||||||
|
COGL_WINSYS_RECTANGLE_STATE_DISABLE :
|
||||||
|
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
||||||
|
|
||||||
|
if ((rect_env = g_getenv ("COGL_PIXMAP_TEXTURE_RECTANGLE")) ||
|
||||||
|
/* For compatibility, we'll also look at the old Clutter
|
||||||
|
environment variable */
|
||||||
|
(rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
|
||||||
|
{
|
||||||
|
if (g_ascii_strcasecmp (rect_env, "force") == 0)
|
||||||
|
context->rectangle_state =
|
||||||
|
COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
||||||
|
else if (g_ascii_strcasecmp (rect_env, "disable") == 0)
|
||||||
|
context->rectangle_state =
|
||||||
|
COGL_WINSYS_RECTANGLE_STATE_DISABLE;
|
||||||
|
else if (g_ascii_strcasecmp (rect_env, "allow"))
|
||||||
|
g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, "
|
||||||
|
"should be 'force' or 'disable'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
try_create_glx_pixmap (CoglContext *context,
|
||||||
|
CoglTexturePixmapX11 *tex_pixmap,
|
||||||
|
gboolean mipmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys;
|
||||||
|
CoglRenderer *renderer;
|
||||||
|
CoglRendererXlib *xlib_renderer;
|
||||||
|
Display *dpy;
|
||||||
|
/* We have to initialize this *opaque* variable because gcc tries to
|
||||||
|
* be too smart for its own good and warns that the variable may be
|
||||||
|
* used uninitialized otherwise. */
|
||||||
|
GLXFBConfig fb_config = (GLXFBConfig)0;
|
||||||
|
int attribs[7];
|
||||||
|
int i = 0;
|
||||||
|
GLenum target;
|
||||||
|
CoglXlibTrapState trap_state;
|
||||||
|
|
||||||
|
renderer = context->display->renderer;
|
||||||
|
xlib_renderer = renderer->winsys;
|
||||||
|
dpy = xlib_renderer->xdpy;
|
||||||
|
|
||||||
|
if (!get_fbconfig_for_depth (context,
|
||||||
|
tex_pixmap->depth, &fb_config,
|
||||||
|
&glx_tex_pixmap->can_mipmap))
|
||||||
|
{
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "No suitable FBConfig found for depth %i",
|
||||||
|
tex_pixmap->depth);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_use_rectangle (context))
|
||||||
|
{
|
||||||
|
target = GLX_TEXTURE_RECTANGLE_EXT;
|
||||||
|
glx_tex_pixmap->can_mipmap = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
target = GLX_TEXTURE_2D_EXT;
|
||||||
|
|
||||||
|
if (!glx_tex_pixmap->can_mipmap)
|
||||||
|
mipmap = FALSE;
|
||||||
|
|
||||||
|
attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
|
||||||
|
|
||||||
|
if (tex_pixmap->depth == 24)
|
||||||
|
attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
|
||||||
|
else if (tex_pixmap->depth == 32)
|
||||||
|
attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
|
||||||
|
attribs[i++] = mipmap;
|
||||||
|
|
||||||
|
attribs[i++] = GLX_TEXTURE_TARGET_EXT;
|
||||||
|
attribs[i++] = target;
|
||||||
|
|
||||||
|
attribs[i++] = None;
|
||||||
|
|
||||||
|
/* We need to trap errors from glXCreatePixmap because it can
|
||||||
|
* sometimes fail during normal usage. For example on NVidia it gets
|
||||||
|
* upset if you try to create two GLXPixmaps for the same drawable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_cogl_renderer_xlib_trap_errors (renderer, &trap_state);
|
||||||
|
|
||||||
|
glx_tex_pixmap->glx_pixmap = glXCreatePixmap (dpy,
|
||||||
|
fb_config,
|
||||||
|
tex_pixmap->pixmap,
|
||||||
|
attribs);
|
||||||
|
glx_tex_pixmap->has_mipmap_space = mipmap;
|
||||||
|
|
||||||
|
XSync (dpy, False);
|
||||||
|
|
||||||
|
if (_cogl_renderer_xlib_untrap_errors (renderer, &trap_state))
|
||||||
|
{
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Failed to create pixmap for %p", tex_pixmap);
|
||||||
|
_cogl_renderer_xlib_trap_errors (renderer, &trap_state);
|
||||||
|
glXDestroyPixmap (dpy, glx_tex_pixmap->glx_pixmap);
|
||||||
|
XSync (dpy, False);
|
||||||
|
_cogl_renderer_xlib_untrap_errors (renderer, &trap_state);
|
||||||
|
|
||||||
|
glx_tex_pixmap->glx_pixmap = None;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap;
|
||||||
|
|
||||||
|
/* FIXME: It should be possible to get to a CoglContext from any
|
||||||
|
* CoglTexture pointer. */
|
||||||
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
|
if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP))
|
||||||
|
{
|
||||||
|
tex_pixmap->winsys = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
glx_tex_pixmap = g_new0 (CoglTexturePixmapGLX, 1);
|
||||||
|
|
||||||
|
glx_tex_pixmap->glx_pixmap = None;
|
||||||
|
glx_tex_pixmap->can_mipmap = FALSE;
|
||||||
|
glx_tex_pixmap->has_mipmap_space = FALSE;
|
||||||
|
|
||||||
|
glx_tex_pixmap->glx_tex = COGL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
glx_tex_pixmap->bind_tex_image_queued = TRUE;
|
||||||
|
glx_tex_pixmap->pixmap_bound = FALSE;
|
||||||
|
|
||||||
|
tex_pixmap->winsys = glx_tex_pixmap;
|
||||||
|
|
||||||
|
if (!try_create_glx_pixmap (ctx, tex_pixmap, FALSE))
|
||||||
|
{
|
||||||
|
tex_pixmap->winsys = NULL;
|
||||||
|
g_free (glx_tex_pixmap);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_glx_pixmap (CoglContext *context,
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap)
|
||||||
|
{
|
||||||
|
CoglXlibTrapState trap_state;
|
||||||
|
CoglRenderer *renderer;
|
||||||
|
CoglRendererXlib *xlib_renderer;
|
||||||
|
CoglRendererGLX *glx_renderer;
|
||||||
|
|
||||||
|
renderer = context->display->renderer;
|
||||||
|
xlib_renderer = renderer->winsys;
|
||||||
|
glx_renderer = renderer->winsys;
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->pixmap_bound)
|
||||||
|
glx_renderer->pf_glXReleaseTexImage (xlib_renderer->xdpy,
|
||||||
|
glx_tex_pixmap->glx_pixmap,
|
||||||
|
GLX_FRONT_LEFT_EXT);
|
||||||
|
|
||||||
|
/* FIXME - we need to trap errors and synchronize here because
|
||||||
|
* of ordering issues between the XPixmap destruction and the
|
||||||
|
* GLXPixmap destruction.
|
||||||
|
*
|
||||||
|
* If the X pixmap is destroyed, the GLX pixmap is destroyed as
|
||||||
|
* well immediately, and thus, when Cogl calls glXDestroyPixmap()
|
||||||
|
* it'll cause a BadDrawable error.
|
||||||
|
*
|
||||||
|
* this is technically a bug in the X server, which should not
|
||||||
|
* destroy either pixmaps until the call to glXDestroyPixmap(); so
|
||||||
|
* at some point we should revisit this code and remove the
|
||||||
|
* trap+sync after verifying that the destruction is indeed safe.
|
||||||
|
*
|
||||||
|
* for reference, see:
|
||||||
|
* http://bugzilla.clutter-project.org/show_bug.cgi?id=2324
|
||||||
|
*/
|
||||||
|
_cogl_renderer_xlib_trap_errors (renderer, &trap_state);
|
||||||
|
glXDestroyPixmap (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap);
|
||||||
|
XSync (xlib_renderer->xdpy, False);
|
||||||
|
_cogl_renderer_xlib_untrap_errors (renderer, &trap_state);
|
||||||
|
|
||||||
|
glx_tex_pixmap->glx_pixmap = None;
|
||||||
|
glx_tex_pixmap->pixmap_bound = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap;
|
||||||
|
|
||||||
|
/* FIXME: It should be possible to get to a CoglContext from any
|
||||||
|
* CoglTexture pointer. */
|
||||||
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||||
|
|
||||||
|
if (!tex_pixmap->winsys)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glx_tex_pixmap = tex_pixmap->winsys;
|
||||||
|
|
||||||
|
free_glx_pixmap (ctx, glx_tex_pixmap);
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->glx_tex)
|
||||||
|
cogl_handle_unref (glx_tex_pixmap->glx_tex);
|
||||||
|
|
||||||
|
tex_pixmap->winsys = NULL;
|
||||||
|
g_free (glx_tex_pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
|
gboolean needs_mipmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys;
|
||||||
|
CoglRendererGLX *glx_renderer;
|
||||||
|
|
||||||
|
/* FIXME: It should be possible to get to a CoglContext from any CoglTexture
|
||||||
|
* pointer. */
|
||||||
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
|
/* If we don't have a GLX pixmap then fallback */
|
||||||
|
if (glx_tex_pixmap->glx_pixmap == None)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
glx_renderer = ctx->display->renderer->winsys;
|
||||||
|
|
||||||
|
/* Lazily create a texture to hold the pixmap */
|
||||||
|
if (glx_tex_pixmap->glx_tex == COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
CoglPixelFormat texture_format;
|
||||||
|
|
||||||
|
texture_format = (tex_pixmap->depth >= 32 ?
|
||||||
|
COGL_PIXEL_FORMAT_RGBA_8888_PRE :
|
||||||
|
COGL_PIXEL_FORMAT_RGB_888);
|
||||||
|
|
||||||
|
if (should_use_rectangle (ctx))
|
||||||
|
{
|
||||||
|
glx_tex_pixmap->glx_tex =
|
||||||
|
_cogl_texture_rectangle_new_with_size (tex_pixmap->width,
|
||||||
|
tex_pixmap->height,
|
||||||
|
COGL_TEXTURE_NO_ATLAS,
|
||||||
|
texture_format);
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->glx_tex)
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p",
|
||||||
|
tex_pixmap);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
|
||||||
|
"texture rectangle could not be created",
|
||||||
|
tex_pixmap);
|
||||||
|
free_glx_pixmap (ctx, glx_tex_pixmap);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glx_tex_pixmap->glx_tex =
|
||||||
|
_cogl_texture_2d_new_with_size (tex_pixmap->width,
|
||||||
|
tex_pixmap->height,
|
||||||
|
COGL_TEXTURE_NO_ATLAS,
|
||||||
|
texture_format);
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->glx_tex)
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p",
|
||||||
|
tex_pixmap);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
|
||||||
|
"texture 2d could not be created",
|
||||||
|
tex_pixmap);
|
||||||
|
free_glx_pixmap (ctx, glx_tex_pixmap);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_mipmap)
|
||||||
|
{
|
||||||
|
/* If we can't support mipmapping then temporarily fallback */
|
||||||
|
if (!glx_tex_pixmap->can_mipmap)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Recreate the GLXPixmap if it wasn't previously created with a
|
||||||
|
* mipmap tree */
|
||||||
|
if (!glx_tex_pixmap->has_mipmap_space)
|
||||||
|
{
|
||||||
|
free_glx_pixmap (ctx, glx_tex_pixmap);
|
||||||
|
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Recreating GLXPixmap with mipmap "
|
||||||
|
"support for %p", tex_pixmap);
|
||||||
|
if (!try_create_glx_pixmap (ctx, tex_pixmap, TRUE))
|
||||||
|
|
||||||
|
{
|
||||||
|
/* If the pixmap failed then we'll permanently fallback
|
||||||
|
* to using XImage. This shouldn't happen. */
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Falling back to XGetImage "
|
||||||
|
"updates for %p because creating the GLXPixmap "
|
||||||
|
"with mipmap support failed", tex_pixmap);
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->glx_tex)
|
||||||
|
cogl_handle_unref (glx_tex_pixmap->glx_tex);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
glx_tex_pixmap->bind_tex_image_queued = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->bind_tex_image_queued)
|
||||||
|
{
|
||||||
|
GLuint gl_handle, gl_target;
|
||||||
|
CoglRendererXlib *xlib_renderer = ctx->display->renderer->winsys;
|
||||||
|
|
||||||
|
cogl_texture_get_gl_texture (glx_tex_pixmap->glx_tex,
|
||||||
|
&gl_handle, &gl_target);
|
||||||
|
|
||||||
|
COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap);
|
||||||
|
|
||||||
|
GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) );
|
||||||
|
|
||||||
|
if (glx_tex_pixmap->pixmap_bound)
|
||||||
|
glx_renderer->pf_glXReleaseTexImage (xlib_renderer->xdpy,
|
||||||
|
glx_tex_pixmap->glx_pixmap,
|
||||||
|
GLX_FRONT_LEFT_EXT);
|
||||||
|
|
||||||
|
glx_renderer->pf_glXBindTexImage (xlib_renderer->xdpy,
|
||||||
|
glx_tex_pixmap->glx_pixmap,
|
||||||
|
GLX_FRONT_LEFT_EXT,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* According to the recommended usage in the spec for
|
||||||
|
* GLX_EXT_texture_pixmap we should release the texture after
|
||||||
|
* we've finished drawing with it and it is undefined what
|
||||||
|
* happens if you render to a pixmap that is bound to a texture.
|
||||||
|
* However that would require the texture backend to know when
|
||||||
|
* Cogl has finished painting and it may be more expensive to
|
||||||
|
* keep unbinding the texture. Leaving it bound appears to work
|
||||||
|
* on Mesa and NVidia drivers and it is also what Compiz does so
|
||||||
|
* it is probably ok */
|
||||||
|
|
||||||
|
glx_tex_pixmap->bind_tex_image_queued = FALSE;
|
||||||
|
glx_tex_pixmap->pixmap_bound = TRUE;
|
||||||
|
|
||||||
|
_cogl_texture_2d_externally_modified (glx_tex_pixmap->glx_tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys;
|
||||||
|
|
||||||
|
glx_tex_pixmap->bind_tex_image_queued = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglHandle
|
||||||
|
_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap)
|
||||||
|
{
|
||||||
|
CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys;
|
||||||
|
|
||||||
|
return glx_tex_pixmap->glx_tex;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
#define __COGL_WINSYS_PRIVATE_H
|
#define __COGL_WINSYS_PRIVATE_H
|
||||||
|
|
||||||
#include "cogl-framebuffer-private.h"
|
#include "cogl-framebuffer-private.h"
|
||||||
|
#ifdef COGL_HAS_XLIB_SUPPORT
|
||||||
|
#include "cogl-texture-pixmap-x11-private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef COGL_HAS_XLIB_SUPPORT
|
#ifdef COGL_HAS_XLIB_SUPPORT
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
@ -120,4 +123,23 @@ void
|
|||||||
_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
|
_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
|
||||||
unsigned int id);
|
unsigned int id);
|
||||||
|
|
||||||
|
#ifdef COGL_HAS_XLIB_SUPPORT
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
|
||||||
|
gboolean needs_mipmap);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_texture_pixmap_x11_damage_notify (
|
||||||
|
CoglTexturePixmapX11 *tex_pixmap);
|
||||||
|
|
||||||
|
CoglHandle
|
||||||
|
_cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __COGL_WINSYS_PRIVATE_H */
|
#endif /* __COGL_WINSYS_PRIVATE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user