From 5b7182c659391160239467f1041a1d755db45bd3 Mon Sep 17 00:00:00 2001 From: Jamey Sharp Date: Sat, 18 Feb 2006 18:12:40 -0800 Subject: [PATCH] Workaround X server bug, fd.o #3210: if a GLXGetFBConfigs request is sent, fix the length field in the reply. --- src/xcb_in.c | 71 +++++++++++++++++++++++++++++++++++++++------------ src/xcb_out.c | 9 ++++++- src/xcbint.h | 9 ++++++- 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/src/xcb_in.c b/src/xcb_in.c index c260b7b..bb973a3 100644 --- a/src/xcb_in.c +++ b/src/xcb_in.c @@ -35,6 +35,11 @@ #include "xcbext.h" #include "xcbint.h" +typedef struct { + unsigned int request; + enum workarounds workaround; +} pending_reply; + typedef struct XCBReplyData { unsigned int request; void *data; @@ -200,7 +205,9 @@ int _xcb_in_init(_xcb_in *in) in->replies = _xcb_map_new(); in->events = _xcb_queue_new(); in->readers = _xcb_list_new(); - if(!in->current_reply || !in->replies || !in->events || !in->readers) + + in->pending_replies = _xcb_queue_new(); + if(!in->current_reply || !in->replies || !in->events || !in->readers || !in->pending_replies) return 0; return 1; @@ -213,11 +220,24 @@ void _xcb_in_destroy(_xcb_in *in) _xcb_map_delete(in->replies, free); _xcb_queue_delete(in->events, free); _xcb_list_delete(in->readers, 0); + _xcb_queue_delete(in->pending_replies, free); } -int _xcb_in_expect_reply(XCBConnection *c, unsigned int request) +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request, enum workarounds workaround) { - /* XXX: currently a no-op */ + if(workaround != WORKAROUND_NONE) + { + pending_reply *pend = malloc(sizeof(pending_reply)); + if(!pend) + return 0; + pend->request = request; + pend->workaround = workaround; + if(!_xcb_queue_enqueue(c->in.pending_replies, pend)) + { + free(pend); + return 0; + } + } return 1; } @@ -234,21 +254,7 @@ int _xcb_in_read_packet(XCBConnection *c) /* Get the response type, length, and sequence number. */ memcpy(&genrep, c->in.queue, sizeof(genrep)); - /* For reply packets, check that the entire packet is available. */ - if(genrep.response_type == 1) - length += genrep.length * 4; - - buf = malloc(length); - if(!buf) - return 0; - if(_xcb_in_read_block(c, buf, length) <= 0) - { - free(buf); - return 0; - } - /* Compute 32-bit sequence number of this packet. */ - /* XXX: do "sequence lost" check here */ if((genrep.response_type & 0x7f) != KeymapNotify) { int lastread = c->in.request_read; @@ -262,6 +268,37 @@ int _xcb_in_read_packet(XCBConnection *c) c->in.request_read += 0x10000; } + /* For reply packets, check that the entire packet is available. */ + if(genrep.response_type == 1) + { + pending_reply *pend = _xcb_list_peek_head(c->in.pending_replies); + if(pend && pend->request == c->in.request_read) + { + switch(pend->workaround) + { + case WORKAROUND_NONE: + break; + case WORKAROUND_GLX_GET_FB_CONFIGS_BUG: + { + CARD32 *p = (CARD32 *) c->in.queue; + genrep.length = p[2] * p[3] * 2; + } + break; + } + free(_xcb_queue_dequeue(c->in.pending_replies)); + } + length += genrep.length * 4; + } + + buf = malloc(length); + if(!buf) + return 0; + if(_xcb_in_read_block(c, buf, length) <= 0) + { + free(buf); + return 0; + } + if(buf[0] == 1) /* response is a reply */ { XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read); diff --git a/src/xcb_out.c b/src/xcb_out.c index b3a556a..a215bcc 100644 --- a/src/xcb_out.c +++ b/src/xcb_out.c @@ -75,6 +75,7 @@ int XCBSendRequest(XCBConnection *c, unsigned int *request, struct iovec *vector struct iovec prefix[2]; CARD16 shortlen = 0; CARD32 longlen = 0; + enum workarounds workaround = WORKAROUND_NONE; assert(c != 0); assert(request != 0); @@ -121,6 +122,12 @@ int XCBSendRequest(XCBConnection *c, unsigned int *request, struct iovec *vector assert(extension && extension->present); ((CARD8 *) prefix[0].iov_base)[0] = extension->major_opcode; ((CARD8 *) prefix[0].iov_base)[1] = req->opcode; + + /* do we need to work around the X server bug described in glx.xml? */ + if(strcmp(req->ext->name, "GLX") && + ((req->opcode == 17 && ((CARD32 *) vector[0].iov_base)[0] == 0x10004) || + req->opcode == 21)) + workaround = WORKAROUND_GLX_GET_FB_CONFIGS_BUG; } else ((CARD8 *) prefix[0].iov_base)[0] = req->opcode; @@ -136,7 +143,7 @@ int XCBSendRequest(XCBConnection *c, unsigned int *request, struct iovec *vector *request = ++c->out.request; if(!req->isvoid) - _xcb_in_expect_reply(c, *request); + _xcb_in_expect_reply(c, *request, workaround); ret = _xcb_out_write_block(c, prefix, i); if(ret > 0) diff --git a/src/xcbint.h b/src/xcbint.h index 057a315..9cb0c30 100644 --- a/src/xcbint.h +++ b/src/xcbint.h @@ -38,6 +38,11 @@ _xcb_assert_sequence_less((c)->out.request_written, (c)->out.request); \ } while(0) +enum workarounds { + WORKAROUND_NONE, + WORKAROUND_GLX_GET_FB_CONFIGS_BUG +}; + /* xcb_list.c */ typedef struct _xcb_list _xcb_list; @@ -125,12 +130,14 @@ typedef struct _xcb_in { _xcb_map *replies; _xcb_queue *events; _xcb_list *readers; + + _xcb_queue *pending_replies; } _xcb_in; int _xcb_in_init(_xcb_in *in); void _xcb_in_destroy(_xcb_in *in); -int _xcb_in_expect_reply(XCBConnection *c, unsigned int request); +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request, enum workarounds workaround); int _xcb_in_read_packet(XCBConnection *c); int _xcb_in_read(XCBConnection *c); -- 2.34.1