summaryrefslogtreecommitdiff
path: root/src/gallium/state_trackers/egl/x11/native_dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/state_trackers/egl/x11/native_dri2.c')
-rw-r--r--src/gallium/state_trackers/egl/x11/native_dri2.c229
1 files changed, 165 insertions, 64 deletions
diff --git a/src/gallium/state_trackers/egl/x11/native_dri2.c b/src/gallium/state_trackers/egl/x11/native_dri2.c
index dbd1a64992..8df58891a0 100644
--- a/src/gallium/state_trackers/egl/x11/native_dri2.c
+++ b/src/gallium/state_trackers/egl/x11/native_dri2.c
@@ -26,6 +26,7 @@
#include "util/u_math.h"
#include "util/u_format.h"
#include "util/u_inlines.h"
+#include "util/u_hash_table.h"
#include "pipe/p_compiler.h"
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
@@ -50,9 +51,13 @@ struct dri2_display {
struct drm_api *api;
struct x11_screen *xscr;
int xscr_number;
+ const char *dri_driver;
+ int dri_major, dri_minor;
struct dri2_config *configs;
int num_configs;
+
+ struct util_hash_table *surfaces;
};
struct dri2_surface {
@@ -62,7 +67,8 @@ struct dri2_surface {
enum pipe_format color_format;
struct dri2_display *dri2dpy;
- unsigned int sequence_number;
+ unsigned int server_stamp;
+ unsigned int client_stamp;
int width, height;
struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS];
uint valid_mask;
@@ -96,65 +102,23 @@ dri2_config(const struct native_config *nconf)
}
/**
- * Get the buffers from the server.
+ * Process the buffers returned by the server.
*/
static void
-dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
+dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
+ struct x11_drawable_buffer *xbufs,
+ int num_xbufs)
{
struct dri2_surface *dri2surf = dri2_surface(nsurf);
struct dri2_display *dri2dpy = dri2surf->dri2dpy;
- unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
- int num_ins, num_outs, att, i;
- struct x11_drawable_buffer *xbufs;
struct pipe_texture templ;
uint valid_mask;
+ int i;
- /* prepare the attachments */
- num_ins = 0;
- for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
- if (native_attachment_mask_test(buffer_mask, att)) {
- unsigned int dri2att;
-
- switch (att) {
- case NATIVE_ATTACHMENT_FRONT_LEFT:
- dri2att = DRI2BufferFrontLeft;
- break;
- case NATIVE_ATTACHMENT_BACK_LEFT:
- dri2att = DRI2BufferBackLeft;
- break;
- case NATIVE_ATTACHMENT_FRONT_RIGHT:
- dri2att = DRI2BufferFrontRight;
- break;
- case NATIVE_ATTACHMENT_BACK_RIGHT:
- dri2att = DRI2BufferBackRight;
- break;
- default:
- assert(0);
- dri2att = 0;
- break;
- }
-
- dri2atts[num_ins] = dri2att;
- num_ins++;
- }
- }
-
- xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
- &dri2surf->width, &dri2surf->height,
- dri2atts, FALSE, num_ins, &num_outs);
-
- /* we should be able to do better... */
- if (xbufs && dri2surf->last_num_xbufs == num_outs &&
- memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
- free(xbufs);
- return;
- }
-
- /* free the old buffers */
+ /* free the old textures */
for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
pipe_texture_reference(&dri2surf->textures[i], NULL);
dri2surf->valid_mask = 0x0;
- dri2surf->sequence_number++;
dri2surf->have_back = FALSE;
dri2surf->have_fake = FALSE;
@@ -172,7 +136,7 @@ dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
valid_mask = 0x0;
- for (i = 0; i < num_outs; i++) {
+ for (i = 0; i < num_xbufs; i++) {
struct x11_drawable_buffer *xbuf = &xbufs[i];
const char *desc;
enum native_attachment natt;
@@ -212,12 +176,72 @@ dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
valid_mask |= 1 << natt;
}
+ dri2surf->valid_mask = valid_mask;
+}
+
+/**
+ * Get the buffers from the server.
+ */
+static void
+dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+ unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
+ int num_ins, num_outs, att;
+ struct x11_drawable_buffer *xbufs;
+
+ /* prepare the attachments */
+ num_ins = 0;
+ for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+ if (native_attachment_mask_test(buffer_mask, att)) {
+ unsigned int dri2att;
+
+ switch (att) {
+ case NATIVE_ATTACHMENT_FRONT_LEFT:
+ dri2att = DRI2BufferFrontLeft;
+ break;
+ case NATIVE_ATTACHMENT_BACK_LEFT:
+ dri2att = DRI2BufferBackLeft;
+ break;
+ case NATIVE_ATTACHMENT_FRONT_RIGHT:
+ dri2att = DRI2BufferFrontRight;
+ break;
+ case NATIVE_ATTACHMENT_BACK_RIGHT:
+ dri2att = DRI2BufferBackRight;
+ break;
+ default:
+ assert(0);
+ dri2att = 0;
+ break;
+ }
+
+ dri2atts[num_ins] = dri2att;
+ num_ins++;
+ }
+ }
+
+ xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
+ &dri2surf->width, &dri2surf->height,
+ dri2atts, FALSE, num_ins, &num_outs);
+
+ /* we should be able to do better... */
+ if (xbufs && dri2surf->last_num_xbufs == num_outs &&
+ memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
+ free(xbufs);
+ dri2surf->client_stamp = dri2surf->server_stamp;
+ return;
+ }
+
+ dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
+
+ dri2surf->server_stamp++;
+ dri2surf->client_stamp = dri2surf->server_stamp;
+
if (dri2surf->last_xbufs)
free(dri2surf->last_xbufs);
dri2surf->last_xbufs = xbufs;
dri2surf->last_num_xbufs = num_outs;
-
- dri2surf->valid_mask = valid_mask;
}
/**
@@ -264,7 +288,7 @@ dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
}
}
dri2surf->valid_mask |= new_valid;
- /* no need to update sequence number */
+ /* no need to update the stamps */
}
else {
dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
@@ -273,6 +297,16 @@ dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
}
+/**
+ * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
+ */
+static INLINE boolean
+dri2_surface_receive_events(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ return (dri2surf->dri2dpy->dri_minor >= 3);
+}
+
static boolean
dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
{
@@ -289,6 +323,10 @@ dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
0, 0, dri2surf->width, dri2surf->height,
DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+ /* force buffers to be updated in next validation call */
+ if (!dri2_surface_receive_events(&dri2surf->base))
+ dri2surf->server_stamp++;
+
return TRUE;
}
@@ -314,6 +352,10 @@ dri2_surface_swap_buffers(struct native_surface *nsurf)
0, 0, dri2surf->width, dri2surf->height,
DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+ /* force buffers to be updated in next validation call */
+ if (!dri2_surface_receive_events(&dri2surf->base))
+ dri2surf->server_stamp++;
+
return TRUE;
}
@@ -324,11 +366,14 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
{
struct dri2_surface *dri2surf = dri2_surface(nsurf);
- if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
- return FALSE;
+ if (dri2surf->server_stamp != dri2surf->client_stamp ||
+ (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
+ if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
+ return FALSE;
+ }
if (seq_num)
- *seq_num = dri2surf->sequence_number;
+ *seq_num = dri2surf->client_stamp;
if (textures) {
int att;
@@ -377,9 +422,13 @@ dri2_surface_destroy(struct native_surface *nsurf)
pipe_texture_reference(&ptex, NULL);
}
- if (dri2surf->drawable)
+ if (dri2surf->drawable) {
x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
dri2surf->drawable, FALSE);
+
+ util_hash_table_remove(dri2surf->dri2dpy->surfaces,
+ (void *) dri2surf->drawable);
+ }
free(dri2surf);
}
@@ -408,8 +457,14 @@ dri2_display_create_surface(struct native_display *ndpy,
dri2surf->base.validate = dri2_surface_validate;
dri2surf->base.wait = dri2_surface_wait;
- if (drawable)
+ if (drawable) {
x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
+ /* initialize the geometry */
+ dri2_surface_update_buffers(&dri2surf->base, 0x0);
+
+ util_hash_table_set(dri2surf->dri2dpy->surfaces,
+ (void *) dri2surf->drawable, (void *) &dri2surf->base);
+ }
return dri2surf;
}
@@ -655,6 +710,9 @@ dri2_display_destroy(struct native_display *ndpy)
if (dri2dpy->base.screen)
dri2dpy->base.screen->destroy(dri2dpy->base.screen);
+ if (dri2dpy->surfaces)
+ util_hash_table_destroy(dri2dpy->surfaces);
+
if (dri2dpy->xscr)
x11_screen_destroy(dri2dpy->xscr);
if (dri2dpy->own_dpy)
@@ -664,6 +722,24 @@ dri2_display_destroy(struct native_display *ndpy)
free(dri2dpy);
}
+static void
+dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
+ void *user_data)
+{
+ struct native_display *ndpy = (struct native_display* ) user_data;
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ struct native_surface *nsurf;
+ struct dri2_surface *dri2surf;
+
+ nsurf = (struct native_surface *)
+ util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
+ if (!nsurf)
+ return;
+
+ dri2surf = dri2_surface(nsurf);
+ dri2surf->server_stamp++;
+}
+
/**
* Initialize DRI2 and pipe screen.
*/
@@ -681,7 +757,17 @@ dri2_display_init_screen(struct native_display *ndpy)
return FALSE;
}
- fd = x11_screen_enable_dri2(dri2dpy->xscr, driver);
+ dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
+ &dri2dpy->dri_major, &dri2dpy->dri_minor);
+ if (!dri2dpy->dri_driver || !driver ||
+ strcmp(dri2dpy->dri_driver, driver) != 0) {
+ _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
+ dri2dpy->dri_driver, dri2dpy->api->name);
+ return FALSE;
+ }
+
+ fd = x11_screen_enable_dri2(dri2dpy->xscr,
+ dri2_display_invalidate_buffers, &dri2dpy->base);
if (fd < 0)
return FALSE;
@@ -696,6 +782,19 @@ dri2_display_init_screen(struct native_display *ndpy)
return TRUE;
}
+static unsigned
+dri2_display_hash_table_hash(void *key)
+{
+ XID drawable = pointer_to_uintptr(key);
+ return (unsigned) drawable;
+}
+
+static int
+dri2_display_hash_table_compare(void *key1, void *key2)
+{
+ return (key1 - key2);
+}
+
struct native_display *
x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
{
@@ -706,11 +805,6 @@ x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
return NULL;
dri2dpy->api = api;
- if (!dri2dpy->api) {
- _eglLog(_EGL_WARNING, "failed to create DRM API");
- free(dri2dpy);
- return NULL;
- }
dri2dpy->dpy = dpy;
if (!dri2dpy->dpy) {
@@ -734,6 +828,13 @@ x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
return NULL;
}
+ dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
+ dri2_display_hash_table_compare);
+ if (!dri2dpy->surfaces) {
+ dri2_display_destroy(&dri2dpy->base);
+ return NULL;
+ }
+
dri2dpy->base.destroy = dri2_display_destroy;
dri2dpy->base.get_configs = dri2_display_get_configs;
dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;