#include <xcb/dri3.h>
#include <xcb/present.h>
#include <GL/gl.h>
-#include "glapi.h"
#include "glxclient.h"
-#include "xf86dri.h"
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
-#include "xf86drm.h"
#include "dri_common.h"
#include "dri3_priv.h"
+#include "loader.h"
+#include "dri2.h"
static const struct glx_context_vtable dri3_context_vtable;
static void
dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer);
+static void
+dri3_update_num_back(struct dri3_drawable *priv)
+{
+ priv->num_back = 1;
+ if (priv->flipping)
+ priv->num_back++;
+ if (priv->swap_interval == 0)
+ priv->num_back++;
+}
+
static void
dri3_destroy_drawable(__GLXDRIdrawable *base)
{
break;
}
+ dri3_update_num_back(pdraw);
+
(void) __glXInitialize(psc->base.dpy);
/* Create a new drawable */
case XCB_PRESENT_COMPLETE_NOTIFY: {
xcb_present_complete_notify_event_t *ce = (void *) ge;
- if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
- priv->present_event_serial = ce->serial;
- else
- priv->present_msc_event_serial = ce->serial;
+ /* Compute the processed SBC number from the received 32-bit serial number merged
+ * with the upper 32-bits of the sent 64-bit serial number while checking for
+ * wrap
+ */
+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
+ priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial;
+ if (priv->recv_sbc > priv->send_sbc)
+ priv->recv_sbc -= 0x100000000;
+ switch (ce->mode) {
+ case XCB_PRESENT_COMPLETE_MODE_FLIP:
+ priv->flipping = true;
+ break;
+ case XCB_PRESENT_COMPLETE_MODE_COPY:
+ priv->flipping = false;
+ break;
+ }
+ dri3_update_num_back(priv);
+ } else {
+ priv->recv_msc_serial = ce->serial;
+ }
priv->ust = ce->ust;
priv->msc = ce->msc;
break;
if (buf && buf->pixmap == ie->pixmap) {
buf->busy = 0;
+ if (priv->num_back <= b && b < DRI3_MAX_BACK) {
+ dri3_free_render_buffer(priv, buf);
+ priv->buffers[b] = NULL;
+ }
break;
}
}
free(ge);
}
+static bool
+dri3_wait_for_event(__GLXDRIdrawable *pdraw)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+ xcb_generic_event_t *ev;
+ xcb_present_generic_event_t *ge;
+
+ xcb_flush(c);
+ ev = xcb_wait_for_special_event(c, priv->special_event);
+ if (!ev)
+ return false;
+ ge = (void *) ev;
+ dri3_handle_present_event(priv, ge);
+ return true;
+}
+
+/** dri3_wait_for_msc
+ *
+ * Get the X server to send an event when the target msc/divisor/remainder is
+ * reached.
+ */
static int
dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
{
xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
- xcb_generic_event_t *ev;
- xcb_present_generic_event_t *ge;
+ uint32_t msc_serial;
/* Ask for the an event for the target MSC */
- ++priv->present_msc_request_serial;
+ msc_serial = ++priv->send_msc_serial;
xcb_present_notify_msc(c,
priv->base.xDrawable,
- priv->present_msc_request_serial,
+ msc_serial,
target_msc,
divisor,
remainder);
/* Wait for the event */
if (priv->special_event) {
- while (priv->present_msc_request_serial != priv->present_msc_event_serial) {
- ev = xcb_wait_for_special_event(c, priv->special_event);
- if (!ev)
- break;
- ge = (void *) ev;
- dri3_handle_present_event(priv, ge);
+ while ((int32_t) (msc_serial - priv->recv_msc_serial) > 0) {
+ if (!dri3_wait_for_event(pdraw))
+ return 0;
}
}
*ust = priv->ust;
*msc = priv->msc;
- *sbc = priv->sbc;
+ *sbc = priv->recv_sbc;
return 1;
}
+/** dri3_drawable_get_msc
+ *
+ * Return the current UST/MSC/SBC triplet by asking the server
+ * for an event
+ */
static int
dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
int64_t *ust, int64_t *msc, int64_t *sbc)
/** dri3_wait_for_sbc
*
- * Wait for the swap buffer count to increase. The only way this
- * can happen is if some other thread is doing swap buffers as
- * we no longer share swap buffer counts with other processes.
- *
- * I'm not sure this is actually useful as such, and so this
- * implementation is a kludge that just polls once a second
+ * Wait for the completed swap buffer count to reach the specified
+ * target. Presumably the application knows that this will be reached with
+ * outstanding complete events, or we're going to be here awhile.
*/
static int
dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
{
struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
- while (priv->sbc < target_sbc) {
- sleep(1);
+ while (priv->recv_sbc < target_sbc) {
+ if (!dri3_wait_for_event(pdraw))
+ return 0;
}
- return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc, sbc);
+
+ *ust = priv->ust;
+ *msc = priv->msc;
+ *sbc = priv->recv_sbc;
+ return 1;
}
/**
/* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
switch (format) {
+ case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
xcb_present_generic_event_t *ge;
for (;;) {
+ for (b = 0; b < priv->num_back; b++) {
+ int id = DRI3_BACK_ID((b + priv->cur_back) % priv->num_back);
+ struct dri3_buffer *buffer = priv->buffers[id];
- for (b = 0; b < DRI3_NUM_BACK; b++) {
- int id = DRI3_BACK_ID(b);
- struct dri3_buffer *buffer = priv->buffers[id];
-
- if (!buffer)
- return b;
- if (!buffer->busy)
- return b;
+ if (!buffer || !buffer->busy) {
+ priv->cur_back = id;
+ return id;
+ }
}
+ xcb_flush(c);
ev = xcb_wait_for_special_event(c, priv->special_event);
if (!ev)
return -1;
int buf_id;
if (buffer_type == dri3_buffer_back) {
- int back = dri3_find_back(c, priv);
+ buf_id = dri3_find_back(c, priv);
- if (back < 0)
+ if (buf_id < 0)
return NULL;
-
- priv->cur_back = back;
- buf_id = DRI3_BACK_ID(priv->cur_back);
} else {
buf_id = DRI3_FRONT_ID;
}
switch (buffer_type) {
case dri3_buffer_back:
first_id = DRI3_BACK_ID(0);
- n_id = DRI3_NUM_BACK;
+ n_id = DRI3_MAX_BACK;
break;
case dri3_buffer_front:
first_id = DRI3_FRONT_ID;
/* The image loader extension record for DRI3
*/
static const __DRIimageLoaderExtension imageLoaderExtension = {
- {__DRI_IMAGE_LOADER, __DRI_IMAGE_LOADER_VERSION},
- .getBuffers = dri3_get_buffers,
- .flushFrontBuffer = dri3_flush_front_buffer,
+ .base = { __DRI_IMAGE_LOADER, 1 },
+
+ .getBuffers = dri3_get_buffers,
+ .flushFrontBuffer = dri3_flush_front_buffer,
+};
+
+static const __DRIextension *loader_extensions[] = {
+ &imageLoaderExtension.base,
+ &systemTimeExtension.base,
+ NULL
};
/** dri3_swap_buffers
/* Compute when we want the frame shown by taking the last known successful
* MSC and adding in a swap interval for each outstanding swap request
*/
- ++priv->present_request_serial;
+ ++priv->send_sbc;
if (target_msc == 0)
- target_msc = priv->msc + priv->swap_interval * (priv->present_request_serial - priv->present_event_serial);
+ target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc);
priv->buffers[buf_id]->busy = 1;
+ priv->buffers[buf_id]->last_swap = priv->send_sbc;
xcb_present_pixmap(c,
priv->base.xDrawable,
priv->buffers[buf_id]->pixmap,
- priv->present_request_serial,
+ (uint32_t) priv->send_sbc,
0, /* valid */
0, /* update */
0, /* x_off */
target_msc,
divisor,
remainder, 0, NULL);
- ret = ++priv->sbc;
+ ret = (int64_t) priv->send_sbc;
/* If there's a fake front, then copy the source back buffer
* to the fake front to keep it up to date. This needs
return ret;
}
+static int
+dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+ int back_id = DRI3_BACK_ID(dri3_find_back(c, priv));
+
+ if (back_id < 0 || !priv->buffers[back_id])
+ return 0;
+
+ if (priv->buffers[back_id]->last_swap != 0)
+ return priv->send_sbc - priv->buffers[back_id]->last_swap + 1;
+ else
+ return 0;
+}
+
/** dri3_open
*
* Wrapper around xcb_dri3_open
xcb_dri3_open_cookie_t cookie;
xcb_dri3_open_reply_t *reply;
xcb_connection_t *c = XGetXCBConnection(dpy);
- xcb_generic_error_t *error;
int fd;
cookie = xcb_dri3_open(c,
root,
provider);
- reply = xcb_dri3_open_reply(c, cookie, &error);
+ reply = xcb_dri3_open_reply(c, cookie, NULL);
if (!reply)
return -1;
}
priv->swap_interval = interval;
+ dri3_update_num_back(priv);
return 0;
}
if (pdraw != NULL) {
psc = (struct dri3_screen *) base->psc;
- if (psc->texBuffer->releaseTexBuffer)
+ if (psc->texBuffer->base.version >= 3 &&
+ psc->texBuffer->releaseTexBuffer != NULL)
(*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
pdraw->base.textureTarget,
pdraw->driDrawable);
}
static const struct glx_context_vtable dri3_context_vtable = {
- dri3_destroy_context,
- dri3_bind_context,
- dri3_unbind_context,
- dri3_wait_gl,
- dri3_wait_x,
- DRI_glXUseXFont,
- dri3_bind_tex_image,
- dri3_release_tex_image,
- NULL, /* get_proc_address */
+ .destroy = dri3_destroy_context,
+ .bind = dri3_bind_context,
+ .unbind = dri3_unbind_context,
+ .wait_gl = dri3_wait_gl,
+ .wait_x = dri3_wait_x,
+ .use_x_font = DRI_glXUseXFont,
+ .bind_tex_image = dri3_bind_tex_image,
+ .release_tex_image = dri3_release_tex_image,
+ .get_proc_address = NULL,
};
/** dri3_bind_extensions
__glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
__glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
__glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
-
- /*
- * GLX_INTEL_swap_event is broken on the server side, where it's
- * currently unconditionally enabled. This completely breaks
- * systems running on drivers which don't support that extension.
- * There's no way to test for its presence on this side, so instead
- * of disabling it unconditionally, just disable it for drivers
- * which are known to not support it, or for DDX drivers supporting
- * only an older (pre-ScheduleSwap) version of DRI2.
- *
- * This is a hack which is required until:
- * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
- * is merged and updated xserver makes it's way into distros:
- */
-// if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
-// __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
-// }
+ __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
mask = psc->image_driver->getAPIMask(psc->driScreen);
if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
__glXEnableDirectExtension(&psc->base,
"GLX_ARB_create_context_robustness");
+
+ if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
+ psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
+ __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
+ }
}
}
static const struct glx_screen_vtable dri3_screen_vtable = {
- dri3_create_context,
- dri3_create_context_attribs
+ .create_context = dri3_create_context,
+ .create_context_attribs = dri3_create_context_attribs,
+ .query_renderer_integer = dri3_query_renderer_integer,
+ .query_renderer_string = dri3_query_renderer_string,
};
/** dri3_create_screen
}
deviceName = NULL;
- driverName = dri3_get_driver_for_fd(psc->fd);
+ driverName = loader_get_driver_for_fd(psc->fd, 0);
if (!driverName) {
ErrorMessageF("No driver found\n");
goto handle_error;
psc->driScreen =
psc->image_driver->createNewScreen2(screen, psc->fd,
- (const __DRIextension **)
- &pdp->loader_extensions[0],
+ pdp->loader_extensions,
extensions,
&driver_configs, psc);
configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
- if (!configs || !visuals)
+ if (!configs || !visuals) {
+ ErrorMessageF("No matching fbConfigs or visuals found\n");
goto handle_error;
+ }
glx_config_destroy_list(psc->base.configs);
psc->base.configs = configs;
psp->copySubBuffer = dri3_copy_sub_buffer;
__glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
+ psp->getBufferAge = dri3_get_buffer_age;
+ __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
+
free(driverName);
free(deviceName);
dri3_create_display(Display * dpy)
{
struct dri3_display *pdp;
- int i;
xcb_connection_t *c = XGetXCBConnection(dpy);
xcb_dri3_query_version_cookie_t dri3_cookie;
xcb_dri3_query_version_reply_t *dri3_reply;
}
pdp->presentMajor = present_reply->major_version;
pdp->presentMinor = present_reply->minor_version;
+ free(present_reply);
pdp->base.destroyDisplay = dri3_destroy_display;
pdp->base.createScreen = dri3_create_screen;
- i = 0;
-
- pdp->loader_extensions[i++] = &imageLoaderExtension.base;
-
- pdp->loader_extensions[i++] = &systemTimeExtension.base;
+ loader_set_logger(dri_message);
- pdp->loader_extensions[i++] = NULL;
+ pdp->loader_extensions = loader_extensions;
return &pdp->base;
no_extension: