dri2: Preserve compatibility with 1.6 DRI2 API/ABI
The old DRI2 buffer allocation API wasn't great, but there's no reason to make the server stop working with those drivers. This patch has the X server adapting to the API provided by the driver, using the new API where available and falling back to the old API as necessary. A warning will be placed in the log file when the old API is in use. Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
		
							parent
							
								
									7c7f0c2c6a
								
							
						
					
					
						commit
						2e2c5b216c
					
				|  | @ -53,7 +53,7 @@ typedef struct _DRI2Drawable { | |||
|     unsigned int	 refCount; | ||||
|     int			 width; | ||||
|     int			 height; | ||||
|     DRI2BufferPtr	*buffers; | ||||
|     DRI2Buffer2Ptr	*buffers; | ||||
|     int			 bufferCount; | ||||
|     unsigned int	 pendingSequence; | ||||
| } DRI2DrawableRec, *DRI2DrawablePtr; | ||||
|  | @ -63,6 +63,10 @@ typedef struct _DRI2Screen { | |||
|     const char			*deviceName; | ||||
|     int				 fd; | ||||
|     unsigned int		 lastSequence; | ||||
| 
 | ||||
|     DRI2CreateBuffersProcPtr	 CreateBuffers; | ||||
|     DRI2DestroyBuffersProcPtr	 DestroyBuffers; | ||||
| 
 | ||||
|     DRI2CreateBufferProcPtr	 CreateBuffer; | ||||
|     DRI2DestroyBufferProcPtr	 DestroyBuffer; | ||||
|     DRI2CopyRegionProcPtr	 CopyRegion; | ||||
|  | @ -133,17 +137,17 @@ DRI2CreateDrawable(DrawablePtr pDraw) | |||
| } | ||||
| 
 | ||||
| static int | ||||
| find_attachment(DRI2BufferPtr *buffer_list, int count, unsigned attachment) | ||||
| find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) | ||||
| { | ||||
|     int i; | ||||
| 
 | ||||
|     if (buffer_list == NULL) { | ||||
|     if (pPriv->buffers == NULL) { | ||||
| 	return -1; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < count; i++) { | ||||
| 	if ((buffer_list[i] != NULL) | ||||
| 	    && (buffer_list[i]->attachment == attachment)) { | ||||
|     for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 	if ((pPriv->buffers[i] != NULL) | ||||
| 	    && (pPriv->buffers[i]->attachment == attachment)) { | ||||
| 	    return i; | ||||
| 	} | ||||
|     } | ||||
|  | @ -151,16 +155,16 @@ find_attachment(DRI2BufferPtr *buffer_list, int count, unsigned attachment) | |||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| static DRI2BufferPtr | ||||
| static DRI2Buffer2Ptr | ||||
| allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, | ||||
| 			 DRI2DrawablePtr pPriv, | ||||
| 			 unsigned int attachment, unsigned int format, | ||||
| 			 int dimensions_match) | ||||
| { | ||||
|     DRI2BufferPtr buffer; | ||||
|     DRI2Buffer2Ptr buffer; | ||||
|     int old_buf; | ||||
| 
 | ||||
|     old_buf = find_attachment(pPriv->buffers, pPriv->bufferCount, attachment); | ||||
|     old_buf = find_attachment(pPriv, attachment); | ||||
| 
 | ||||
|     if ((old_buf < 0) | ||||
| 	|| !dimensions_match | ||||
|  | @ -174,14 +178,14 @@ allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, | |||
|     return buffer; | ||||
| } | ||||
| 
 | ||||
| static DRI2BufferPtr * | ||||
| static DRI2Buffer2Ptr * | ||||
| do_get_buffers(DrawablePtr pDraw, int *width, int *height, | ||||
| 	       unsigned int *attachments, int count, int *out_count, | ||||
| 	       int has_format) | ||||
| { | ||||
|     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen); | ||||
|     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); | ||||
|     DRI2BufferPtr  *buffers; | ||||
|     DRI2Buffer2Ptr  *buffers; | ||||
|     int need_real_front = 0; | ||||
|     int need_fake_front = 0; | ||||
|     int have_fake_front = 0; | ||||
|  | @ -201,67 +205,155 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, | |||
| 
 | ||||
|     buffers = xalloc((count + 1) * sizeof(buffers[0])); | ||||
| 
 | ||||
|     for (i = 0; i < count; i++) { | ||||
| 	const unsigned attachment = *(attachments++); | ||||
| 	const unsigned format = (has_format) ? *(attachments++) : 0; | ||||
|     if (ds->CreateBuffer) { | ||||
| 	/* Version 2 API with CreateBuffer */ | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 	    const unsigned attachment = *(attachments++); | ||||
| 	    const unsigned format = (has_format) ? *(attachments++) : 0; | ||||
| 
 | ||||
| 	buffers[i] = allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, | ||||
| 					      format, dimensions_match); | ||||
| 	    buffers[i] = allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, | ||||
| 						  format, dimensions_match); | ||||
| 
 | ||||
| 	    /* If the drawable is a window and the front-buffer is requested,
 | ||||
| 	     * silently add the fake front-buffer to the list of requested | ||||
| 	     * attachments.  The counting logic in the loop accounts for the case | ||||
| 	     * where the client requests both the fake and real front-buffer. | ||||
| 	     */ | ||||
| 	    if (attachment == DRI2BufferBackLeft) { | ||||
| 		need_real_front++; | ||||
| 		front_format = format; | ||||
| 	    } | ||||
| 
 | ||||
| 	/* If the drawable is a window and the front-buffer is requested,
 | ||||
| 	 * silently add the fake front-buffer to the list of requested | ||||
| 	 * attachments.  The counting logic in the loop accounts for the case | ||||
| 	 * where the client requests both the fake and real front-buffer. | ||||
| 	 */ | ||||
| 	if (attachment == DRI2BufferBackLeft) { | ||||
| 	    need_real_front++; | ||||
| 	    front_format = format; | ||||
| 	} | ||||
| 	    if (attachment == DRI2BufferFrontLeft) { | ||||
| 		need_real_front--; | ||||
| 		front_format = format; | ||||
| 
 | ||||
| 	if (attachment == DRI2BufferFrontLeft) { | ||||
| 	    need_real_front--; | ||||
| 	    front_format = format; | ||||
| 		if (pDraw->type == DRAWABLE_WINDOW) { | ||||
| 		    need_fake_front++; | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	    if (pDraw->type == DRAWABLE_WINDOW) { | ||||
| 		need_fake_front++; | ||||
| 		if (attachment == DRI2BufferFakeFrontLeft) { | ||||
| 		    need_fake_front--; | ||||
| 		    have_fake_front = 1; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
| 	if (pDraw->type == DRAWABLE_WINDOW) { | ||||
| 	    if (attachment == DRI2BufferFakeFrontLeft) { | ||||
| 	if (need_real_front > 0) { | ||||
| 	    buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv, | ||||
| 						    DRI2BufferFrontLeft, | ||||
| 						    front_format, dimensions_match); | ||||
| 	} | ||||
| 
 | ||||
| 	if (need_fake_front > 0) { | ||||
| 	    buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv, | ||||
| 						    DRI2BufferFakeFrontLeft, | ||||
| 						    front_format, dimensions_match); | ||||
| 	    have_fake_front = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	*out_count = i; | ||||
| 
 | ||||
| 
 | ||||
| 	if (pPriv->buffers != NULL) { | ||||
| 	    for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 		if (pPriv->buffers[i] != NULL) { | ||||
| 		    (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	    xfree(pPriv->buffers); | ||||
| 	} | ||||
|     } else { | ||||
| 	DRI2BufferPtr	buffers1; | ||||
| 	unsigned int	temp_buf[32]; | ||||
| 	unsigned int	*temp = temp_buf; | ||||
| 	int		i; | ||||
| 	int		buffers_match = 1; | ||||
| 
 | ||||
| 	/* Version 1 API with CreateBuffers */ | ||||
| 
 | ||||
| 	if ((count + 1) > 32) { | ||||
| 	    temp = xalloc((count + 1) * sizeof(temp[0])); | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 	    const unsigned attachment = *(attachments++); | ||||
| 
 | ||||
| 	    /* Version 1 doesn't deal with the format at all */ | ||||
| 	    if (has_format) | ||||
| 		attachments++; | ||||
| 
 | ||||
| 	    /*
 | ||||
| 	     * Make sure the client also gets the front buffer when | ||||
| 	     * it asks for a back buffer | ||||
| 	     */ | ||||
| 	    if (attachment == DRI2BufferBackLeft) | ||||
| 		need_real_front++; | ||||
| 
 | ||||
| 	    /*
 | ||||
| 	     * If the drawable is a window and the front-buffer is requested, | ||||
| 	     * silently add the fake front-buffer to the list of requested | ||||
| 	     * attachments.  The counting logic in the loop accounts for the | ||||
| 	     * case where the client requests both the fake and real | ||||
| 	     * front-buffer. | ||||
| 	     */ | ||||
| 	    if (attachment == DRI2BufferFrontLeft) { | ||||
| 		need_real_front--; | ||||
| 		if (pDraw->type == DRAWABLE_WINDOW) | ||||
| 		    need_fake_front++; | ||||
| 	    } | ||||
| 	    if (pDraw->type == DRAWABLE_WINDOW && | ||||
| 		attachment == DRI2BufferFakeFrontLeft) | ||||
| 	    { | ||||
| 		need_fake_front--; | ||||
| 		have_fake_front = 1; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     if (need_real_front > 0) { | ||||
| 	buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv, | ||||
| 						DRI2BufferFrontLeft, | ||||
| 						front_format, dimensions_match); | ||||
|     } | ||||
| 
 | ||||
|     if (need_fake_front > 0) { | ||||
| 	buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv, | ||||
| 						DRI2BufferFakeFrontLeft, | ||||
| 						front_format, dimensions_match); | ||||
| 	have_fake_front = 1; | ||||
|     } | ||||
| 
 | ||||
|     *out_count = i; | ||||
| 
 | ||||
| 
 | ||||
|     if (pPriv->buffers != NULL) { | ||||
| 	for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 	    if (pPriv->buffers[i] != NULL) { | ||||
| 		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); | ||||
| 	    } | ||||
| 	    temp[i] = attachment; | ||||
| 	} | ||||
| 
 | ||||
| 	xfree(pPriv->buffers); | ||||
|     } | ||||
| 	if (need_real_front > 0) | ||||
| 	    temp[count++] = DRI2BufferFrontLeft; | ||||
| 
 | ||||
| 	if (need_fake_front > 0) { | ||||
| 	    temp[count++] = DRI2BufferFakeFrontLeft; | ||||
| 	    have_fake_front = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (count != pPriv->bufferCount) | ||||
| 	    buffers_match = 0; | ||||
| 	else { | ||||
| 	    for (i = 0; i < count; i++) | ||||
| 		if (pPriv->buffers[i]->attachment != temp[i]) { | ||||
| 		    buffers_match = 0; | ||||
| 		    break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (pPriv->buffers == NULL || !dimensions_match || !buffers_match) | ||||
| 	{ | ||||
|             buffers1 = (*ds->CreateBuffers)(pDraw, temp, count); | ||||
| 	    if (pPriv->buffers != NULL) | ||||
| 		(*ds->DestroyBuffers)(pDraw, (DRI2BufferPtr) pPriv->buffers[0], | ||||
| 				      pPriv->bufferCount); | ||||
| 	} | ||||
| 	else | ||||
| 	    buffers1 = (DRI2BufferPtr) pPriv->buffers[0]; | ||||
| 
 | ||||
|         for (i = 0; i < count; i++) | ||||
| 	    buffers[i] = (DRI2Buffer2Ptr) &buffers1[i]; | ||||
| 
 | ||||
|         *out_count = count; | ||||
| 
 | ||||
| 	if (pPriv->buffers) | ||||
| 	    xfree (pPriv->buffers); | ||||
| 
 | ||||
| 	if (temp != temp_buf) { | ||||
| 	    xfree(temp); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     pPriv->buffers = buffers; | ||||
|     pPriv->bufferCount = *out_count; | ||||
|  | @ -292,7 +384,7 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, | |||
|     return pPriv->buffers; | ||||
| } | ||||
| 
 | ||||
| DRI2BufferPtr * | ||||
| DRI2Buffer2Ptr * | ||||
| DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, | ||||
| 	       unsigned int *attachments, int count, int *out_count) | ||||
| { | ||||
|  | @ -300,7 +392,7 @@ DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, | |||
| 			  out_count, FALSE); | ||||
| } | ||||
| 
 | ||||
| DRI2BufferPtr * | ||||
| DRI2Buffer2Ptr * | ||||
| DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, | ||||
| 			 unsigned int *attachments, int count, int *out_count) | ||||
| { | ||||
|  | @ -326,9 +418,9 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, | |||
|     for (i = 0; i < pPriv->bufferCount; i++) | ||||
|     { | ||||
| 	if (pPriv->buffers[i]->attachment == dest) | ||||
| 	    pDestBuffer = pPriv->buffers[i]; | ||||
| 	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; | ||||
| 	if (pPriv->buffers[i]->attachment == src) | ||||
| 	    pSrcBuffer = pPriv->buffers[i]; | ||||
| 	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; | ||||
|     } | ||||
|     if (pSrcBuffer == NULL || pDestBuffer == NULL) | ||||
| 	return BadValue; | ||||
|  | @ -357,8 +449,13 @@ DRI2DestroyDrawable(DrawablePtr pDraw) | |||
|     if (pPriv->buffers != NULL) { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 	    (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); | ||||
| 	if (ds->DestroyBuffer) { | ||||
| 	    for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); | ||||
| 	    } | ||||
| 	} else { | ||||
| 	    (*ds->DestroyBuffers)(pDraw, (DRI2BufferPtr) pPriv->buffers[0], | ||||
| 				  pPriv->bufferCount); | ||||
| 	} | ||||
| 
 | ||||
| 	xfree(pPriv->buffers); | ||||
|  | @ -417,18 +514,36 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) | |||
|     if (!ds) | ||||
| 	return FALSE; | ||||
| 
 | ||||
|     if ((info->version < 2) | ||||
| 	|| (info->CreateBuffer == NULL) | ||||
| 	|| (info->DestroyBuffer == NULL)) { | ||||
| 	return FALSE; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     ds->fd	       = info->fd; | ||||
|     ds->driverName     = info->driverName; | ||||
|     ds->deviceName     = info->deviceName; | ||||
|     ds->CreateBuffer   = info->CreateBuffer; | ||||
|     ds->DestroyBuffer  = info->DestroyBuffer; | ||||
| 
 | ||||
|     /* Prefer the new one-at-a-time buffer API */ | ||||
|     if (info->version >= 2 && info->CreateBuffer && info->DestroyBuffer) { | ||||
| 	ds->CreateBuffer   = info->CreateBuffer; | ||||
| 	ds->DestroyBuffer  = info->DestroyBuffer; | ||||
| 	ds->CreateBuffers  = NULL; | ||||
| 	ds->DestroyBuffers = NULL; | ||||
|     } else if (info->CreateBuffers && info->DestroyBuffers) { | ||||
| 	xf86DrvMsg(pScreen->myNum, X_WARNING, | ||||
| 		   "[DRI2] Version 1 API (broken front buffer rendering)\n"); | ||||
| 	ds->CreateBuffer   = NULL; | ||||
| 	ds->DestroyBuffer  = NULL; | ||||
| 	ds->CreateBuffers  = info->CreateBuffers; | ||||
| 	ds->DestroyBuffers = info->DestroyBuffers; | ||||
|     } else { | ||||
| 	xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] Missing buffer management functions\n"); | ||||
| 	xfree(ds); | ||||
| 	return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     if (!info->CopyRegion) { | ||||
| 	xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] Missing copy region function\n"); | ||||
| 	xfree(ds); | ||||
| 	return FALSE; | ||||
|     } | ||||
|     ds->CopyRegion     = info->CopyRegion; | ||||
| 
 | ||||
|     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); | ||||
|  |  | |||
|  | @ -35,16 +35,27 @@ | |||
| 
 | ||||
| #include <X11/extensions/dri2tokens.h> | ||||
| 
 | ||||
| /* Version 1 structure (for ABI compatibility) */ | ||||
| typedef struct { | ||||
|     unsigned int attachment; | ||||
|     unsigned int name; | ||||
|     unsigned int pitch; | ||||
|     unsigned int cpp; | ||||
|     unsigned int flags; | ||||
|     unsigned int format; | ||||
|     void *driverPrivate; | ||||
| } DRI2BufferRec, *DRI2BufferPtr; | ||||
| 
 | ||||
| /* Version 2 structure (with format at the end) */ | ||||
| typedef struct { | ||||
|     unsigned int attachment; | ||||
|     unsigned int name; | ||||
|     unsigned int pitch; | ||||
|     unsigned int cpp; | ||||
|     unsigned int flags; | ||||
|     void *driverPrivate; | ||||
|     unsigned int format; | ||||
| } DRI2Buffer2Rec, *DRI2Buffer2Ptr; | ||||
| 
 | ||||
| typedef DRI2BufferPtr	(*DRI2CreateBuffersProcPtr)(DrawablePtr pDraw, | ||||
| 						    unsigned int *attachments, | ||||
| 						    int count); | ||||
|  | @ -59,11 +70,11 @@ typedef void		(*DRI2CopyRegionProcPtr)(DrawablePtr pDraw, | |||
| typedef void		(*DRI2WaitProcPtr)(WindowPtr pWin, | ||||
| 					   unsigned int sequence); | ||||
| 
 | ||||
| typedef DRI2BufferPtr	(*DRI2CreateBufferProcPtr)(DrawablePtr pDraw, | ||||
| typedef DRI2Buffer2Ptr	(*DRI2CreateBufferProcPtr)(DrawablePtr pDraw, | ||||
| 						   unsigned int attachment, | ||||
| 						   unsigned int format); | ||||
| typedef void		(*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw, | ||||
| 						    DRI2BufferPtr buffer); | ||||
| 						    DRI2Buffer2Ptr buffer); | ||||
| 
 | ||||
| /**
 | ||||
|  * Version of the DRI2InfoRec structure defined in this header | ||||
|  | @ -108,7 +119,7 @@ extern _X_EXPORT int DRI2CreateDrawable(DrawablePtr pDraw); | |||
| 
 | ||||
| extern _X_EXPORT void DRI2DestroyDrawable(DrawablePtr pDraw); | ||||
| 
 | ||||
| extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffers(DrawablePtr pDraw, | ||||
| extern _X_EXPORT DRI2Buffer2Ptr *DRI2GetBuffers(DrawablePtr pDraw, | ||||
| 			     int *width, | ||||
| 			     int *height, | ||||
| 			     unsigned int *attachments, | ||||
|  | @ -138,7 +149,7 @@ extern _X_EXPORT int DRI2CopyRegion(DrawablePtr pDraw, | |||
|  */ | ||||
| extern _X_EXPORT void DRI2Version(int *major, int *minor); | ||||
| 
 | ||||
| extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw, | ||||
| extern _X_EXPORT DRI2Buffer2Ptr *DRI2GetBuffersWithFormat(DrawablePtr pDraw, | ||||
| 	int *width, int *height, unsigned int *attachments, int count, | ||||
| 	int *out_count); | ||||
| 
 | ||||
|  |  | |||
|  | @ -195,7 +195,7 @@ ProcDRI2DestroyDrawable(ClientPtr client) | |||
| 
 | ||||
| static void | ||||
| send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, | ||||
| 		   DRI2BufferPtr *buffers, int count, int width, int height) | ||||
| 		   DRI2Buffer2Ptr *buffers, int count, int width, int height) | ||||
| { | ||||
|     xDRI2GetBuffersReply rep; | ||||
|     int skip = 0; | ||||
|  | @ -245,7 +245,7 @@ ProcDRI2GetBuffers(ClientPtr client) | |||
| { | ||||
|     REQUEST(xDRI2GetBuffersReq); | ||||
|     DrawablePtr pDrawable; | ||||
|     DRI2BufferPtr *buffers; | ||||
|     DRI2Buffer2Ptr *buffers; | ||||
|     int status, width, height, count; | ||||
|     unsigned int *attachments; | ||||
| 
 | ||||
|  | @ -268,7 +268,7 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client) | |||
| { | ||||
|     REQUEST(xDRI2GetBuffersReq); | ||||
|     DrawablePtr pDrawable; | ||||
|     DRI2BufferPtr *buffers; | ||||
|     DRI2Buffer2Ptr *buffers; | ||||
|     int status, width, height, count; | ||||
|     unsigned int *attachments; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue