* Kristian Høgsberg (krh@redhat.com)
*/
-#ifdef GLX_DIRECT_RENDERING
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include "xf86drm.h"
#include "dri2.h"
#include "dri_common.h"
-#include "../../mesa/drivers/dri/common/dri_util.h"
+
+/* From xmlpool/options.h, user exposed so should be stable */
+#define DRI_CONF_VBLANK_NEVER 0
+#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
+#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
+#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
#undef DRI2_MINOR
#define DRI2_MINOR 1
int driMinor;
int driPatch;
int swapAvailable;
+ int invalidateAvailable;
+
+ __glxHashTable *dri2Hash;
+
+ const __DRIextension *loader_extensions[4];
};
struct __GLXDRIcontextPrivateRec
int swap_interval;
};
-static void dri2WaitX(__GLXDRIdrawable * pdraw);
-
static void
dri2DestroyContext(__GLXDRIcontext * context,
__GLXscreenConfigs * psc, Display * dpy)
}
static void
-dri2DestroyDrawable(__GLXDRIdrawable * pdraw)
+dri2DestroyDrawable(__GLXDRIdrawable *pdraw)
{
const __DRIcoreExtension *core = pdraw->psc->core;
+ __GLXdisplayPrivate *dpyPriv;
+ __GLXDRIdisplayPrivate *pdp;
+
+ dpyPriv = __glXInitialize(pdraw->psc->dpy);
+ pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;
+ __glxHashDelete(pdp->dri2Hash, pdraw->xDrawable);
(*core->destroyDrawable) (pdraw->driDrawable);
DRI2DestroyDrawable(pdraw->psc->dpy, pdraw->xDrawable);
Xfree(pdraw);
{
__GLXDRIdrawablePrivate *pdraw;
__GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
+ __GLXdisplayPrivate *dpyPriv;
+ __GLXDRIdisplayPrivate *pdp;
+ GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
pdraw = Xmalloc(sizeof(*pdraw));
if (!pdraw)
pdraw->base.drawable = drawable;
pdraw->base.psc = psc;
pdraw->bufferCount = 0;
+ pdraw->swap_interval = 1; /* default may be overridden below */
+ pdraw->have_back = 0;
+
+ if (psc->config)
+ psc->config->configQueryi(psc->__driScreen, "vblank_mode", &vblank_mode);
+
+ switch (vblank_mode) {
+ case DRI_CONF_VBLANK_NEVER:
+ case DRI_CONF_VBLANK_DEF_INTERVAL_0:
+ pdraw->swap_interval = 0;
+ break;
+ case DRI_CONF_VBLANK_DEF_INTERVAL_1:
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:
+ default:
+ pdraw->swap_interval = 1;
+ break;
+ }
DRI2CreateDrawable(psc->dpy, xDrawable);
+ dpyPriv = __glXInitialize(psc->dpy);
+ pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;;
/* Create a new drawable */
pdraw->base.driDrawable =
(*psc->dri2->createNewDrawable) (psc->__driScreen,
return NULL;
}
+ if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
+ (*psc->core->destroyDrawable) (pdraw->base.driDrawable);
+ DRI2DestroyDrawable(psc->dpy, xDrawable);
+ Xfree(pdraw);
+ return None;
+ }
+
+
+#ifdef X_DRI2SwapInterval
+ /*
+ * Make sure server has the same swap interval we do for the new
+ * drawable.
+ */
+ if (pdp->swapAvailable)
+ DRI2SwapInterval(psc->dpy, xDrawable, pdraw->swap_interval);
+#endif
+
return &pdraw->base;
}
+#ifdef X_DRI2GetMSC
+
static int
dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw,
int64_t *ust, int64_t *msc, int64_t *sbc)
return DRI2GetMSC(psc->dpy, pdraw->xDrawable, ust, msc, sbc);
}
+#endif
+
+
+#ifdef X_DRI2WaitMSC
+
static int
dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
sbc);
}
+#endif /* X_DRI2WaitMSC */
+
static void
dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height)
{
/* Refresh the fake front (if present) after we just damaged the real
* front.
*/
- dri2WaitX(pdraw);
+ DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region,
+ DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+ XFixesDestroyRegion(pdraw->psc->dpy, region);
}
static void
XFixesDestroyRegion(pdraw->psc->dpy, region);
}
-
static void
-dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate)
+dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
{
- (void) driDrawable;
- dri2WaitGL((__GLXDRIdrawable *) loaderPrivate);
+ __GLXDRIdrawablePrivate *pdraw = loaderPrivate;
+ __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy);
+ __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *)priv->dri2Display;
+
+ /* Old servers don't send invalidate events */
+ if (!pdp->invalidateAvailable)
+ dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
+
+ dri2WaitGL(loaderPrivate);
}
(*pdraw->psc->f->flush)(pdraw->driDrawable);
#endif
+ /* Old servers don't send invalidate events */
+ if (!pdp->invalidateAvailable)
+ dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
+
/* Old servers can't handle swapbuffers */
if (!pdp->swapAvailable) {
dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
remainder, &ret);
#endif
-#if __DRI2_FLUSH_VERSION >= 2
- if (pdraw->psc->f)
- (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable);
-#endif
-
return ret;
}
return pdraw->buffers;
}
+#ifdef X_DRI2SwapInterval
+
static void
dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
{
+ __GLXscreenConfigs *psc = pdraw->psc;
__GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw;
+ GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
+
+ if (psc->config)
+ psc->config->configQueryi(psc->__driScreen, "vblank_mode", &vblank_mode);
+
+ switch (vblank_mode) {
+ case DRI_CONF_VBLANK_NEVER:
+ return;
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:
+ if (interval <= 0)
+ return;
+ break;
+ default:
+ break;
+ }
DRI2SwapInterval(priv->base.psc->dpy, pdraw->xDrawable, interval);
priv->swap_interval = interval;
return priv->swap_interval;
}
+#endif /* X_DRI2SwapInterval */
+
static const __DRIdri2LoaderExtension dri2LoaderExtension = {
{__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
dri2GetBuffers,
NULL,
};
-static const __DRIextension *loader_extensions[] = {
- &dri2LoaderExtension.base,
- &systemTimeExtension.base,
- NULL
+#ifdef __DRI_USE_INVALIDATE
+static const __DRIuseInvalidateExtension dri2UseInvalidate = {
+ { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
};
+#endif
+
+_X_HIDDEN void
+dri2InvalidateBuffers(Display *dpy, XID drawable)
+{
+ __GLXDRIdrawable *pdraw =
+ dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
-static const __DRIextension *loader_extensions_old[] = {
- &dri2LoaderExtension_old.base,
- &systemTimeExtension.base,
- NULL
+#if __DRI2_FLUSH_VERSION >= 3
+ if (pdraw && pdraw->psc->f)
+ pdraw->psc->f->invalidate(pdraw->driDrawable);
+#endif
+}
+
+static void
+dri2_bind_tex_image(Display * dpy,
+ GLXDrawable drawable,
+ int buffer, const int *attrib_list)
+{
+ GLXContext gc = __glXGetCurrentContext();
+ __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, NULL);
+ __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
+ __GLXDRIdisplayPrivate *pdp =
+ (__GLXDRIdisplayPrivate *) dpyPriv->dri2Display;
+
+ if (pdraw != NULL) {
+
+#if __DRI2_FLUSH_VERSION >= 3
+ if (!pdp->invalidateAvailable && pdraw->psc->f)
+ pdraw->psc->f->invalidate(pdraw->driDrawable);
+#endif
+
+ if (pdraw->psc->texBuffer->base.version >= 2 &&
+ pdraw->psc->texBuffer->setTexBuffer2 != NULL) {
+ (*pdraw->psc->texBuffer->setTexBuffer2) (gc->__driContext,
+ pdraw->textureTarget,
+ pdraw->textureFormat,
+ pdraw->driDrawable);
+ }
+ else {
+ (*pdraw->psc->texBuffer->setTexBuffer) (gc->__driContext,
+ pdraw->textureTarget,
+ pdraw->driDrawable);
+ }
+ }
+}
+
+static void
+dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
+{
+}
+
+static const struct glx_context_vtable dri2_context_vtable = {
+ dri2_bind_tex_image,
+ dri2_release_tex_image,
};
static __GLXDRIscreen *
if (psp == NULL)
return NULL;
- /* Initialize per screen dynamic client GLX extensions */
- psc->ext_list_first_time = GL_TRUE;
-
if (!DRI2Connect(psc->dpy, RootWindow(psc->dpy, screen),
&driverName, &deviceName)) {
XFree(psp);
goto handle_error;
}
+
/* If the server does not support the protocol for
* DRI2GetBuffersWithFormat, don't supply that interface to the driver.
*/
psc->__driScreen =
- psc->dri2->createNewScreen(screen, psc->fd, ((pdp->driMinor < 1)
- ? loader_extensions_old
- : loader_extensions),
+ psc->dri2->createNewScreen(screen, psc->fd,
+ (const __DRIextension **)
+ &pdp->loader_extensions[0],
&driver_configs, psc);
if (psc->__driScreen == NULL) {
#ifdef X_DRI2SwapInterval
psp->setSwapInterval = dri2SetSwapInterval;
psp->getSwapInterval = dri2GetSwapInterval;
+#endif
+#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
+ __glXEnableDirectExtension(psc, "GLX_OML_sync_control");
#endif
}
psp->copySubBuffer = dri2CopySubBuffer;
__glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer");
+ psc->direct_context_vtable = &dri2_context_vtable;
+
Xfree(driverName);
Xfree(deviceName);
Xfree(dpy);
}
+_X_HIDDEN __GLXDRIdrawable *
+dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
+{
+ __GLXdisplayPrivate *d = __glXInitialize(dpy);
+ __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *) d->dri2Display;
+ __GLXDRIdrawable *pdraw;
+
+ if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
+ return pdraw;
+
+ return NULL;
+}
+
/*
* Allocate, initialize and return a __DRIdisplayPrivate object.
* This is called from __glXInitialize() when we are given a new
dri2CreateDisplay(Display * dpy)
{
__GLXDRIdisplayPrivate *pdp;
- int eventBase, errorBase;
+ int eventBase, errorBase, i;
if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
return NULL;
}
pdp->driPatch = 0;
- pdp->swapAvailable = 0;
-#ifdef X_DRI2SwapBuffers
- if (pdp->driMinor >= 2)
- pdp->swapAvailable = 1;
-#endif
+ pdp->swapAvailable = (pdp->driMinor >= 2);
+ pdp->invalidateAvailable = (pdp->driMinor >= 3);
pdp->base.destroyDisplay = dri2DestroyDisplay;
pdp->base.createScreen = dri2CreateScreen;
+ i = 0;
+ if (pdp->driMinor < 1)
+ pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
+ else
+ pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
+
+ pdp->loader_extensions[i++] = &systemTimeExtension.base;
+
+#ifdef __DRI_USE_INVALIDATE
+ pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
+#endif
+ pdp->loader_extensions[i++] = NULL;
+
+ pdp->dri2Hash = __glxHashCreate();
+ if (pdp->dri2Hash == NULL) {
+ Xfree(pdp);
+ return NULL;
+ }
+
return &pdp->base;
}