From aa2691547281a09da86f7fcc3f991b92a29fc9c7 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 14 Jun 2005 22:51:44 +0000 Subject: [PATCH] Adds support for MGA DRM version 3.2. This patch makes use of two of the new ioctls added in MGA DRM version 3.2. Specifically, the DRM_MGA_SET_FENCE and DRM_MGA_WAIT_FENCE ioctls are used in mgaWaitForFrameCompletion. As a result the MMIO register region and the primary DMA region are *not* mapped (if DRM 3.2 is available). This patch does *not* make use of the new get_param query was added to differentiate between G4x0 cards and G550 cards. That is left to a future update. Xorg bug: 3259 Reviewed by: Eric Anholt --- src/mesa/drivers/dri/mga/mga_xmesa.c | 35 ++++-- src/mesa/drivers/dri/mga/mgacontext.h | 3 + src/mesa/drivers/dri/mga/mgadd.c | 2 +- src/mesa/drivers/dri/mga/mgaioctl.c | 167 +++++++++++++++++--------- 4 files changed, 134 insertions(+), 73 deletions(-) diff --git a/src/mesa/drivers/dri/mga/mga_xmesa.c b/src/mesa/drivers/dri/mga/mga_xmesa.c index aa4cfe5ccde..44e69dd1de4 100644 --- a/src/mesa/drivers/dri/mga/mga_xmesa.c +++ b/src/mesa/drivers/dri/mga/mga_xmesa.c @@ -31,6 +31,7 @@ */ #include +#include #include "drm.h" #include "mga_drm.h" #include "mga_xmesa.h" @@ -264,22 +265,30 @@ mgaInitDriver(__DRIscreenPrivate *sPriv) * primary DMA region base address needs to be known is so that the driver * can busy wait for certain DMA operations to complete (see * mgaWaitForFrameCompletion in mgaioctl.c). + * + * Starting with MGA DRM version 3.2, these are completely unneeded as + * there is a new, in-kernel mechanism for handling the wait. */ - mgaScreen->mmio.handle = serverInfo->registers.handle; - mgaScreen->mmio.size = serverInfo->registers.size; - if ( drmMap( sPriv->fd, - mgaScreen->mmio.handle, mgaScreen->mmio.size, - &mgaScreen->mmio.map ) < 0 ) { - FREE( mgaScreen ); - sPriv->private = NULL; - __driUtilMessage( "Couldn't map MMIO registers" ); - return GL_FALSE; - } - - mgaScreen->primary.handle = serverInfo->primary.handle; - mgaScreen->primary.size = serverInfo->primary.size; + if (mgaScreen->sPriv->drmMinor < 2) { + mgaScreen->mmio.handle = serverInfo->registers.handle; + mgaScreen->mmio.size = serverInfo->registers.size; + if ( drmMap( sPriv->fd, + mgaScreen->mmio.handle, mgaScreen->mmio.size, + &mgaScreen->mmio.map ) < 0 ) { + FREE( mgaScreen ); + sPriv->private = NULL; + __driUtilMessage( "Couldn't map MMIO registers" ); + return GL_FALSE; + } + mgaScreen->primary.handle = serverInfo->primary.handle; + mgaScreen->primary.size = serverInfo->primary.size; + } + else { + (void) memset( & mgaScreen->primary, 0, sizeof( mgaScreen->primary ) ); + (void) memset( & mgaScreen->mmio, 0, sizeof( mgaScreen->mmio ) ); + } mgaScreen->textureOffset[MGA_CARD_HEAP] = serverInfo->textureOffset; mgaScreen->textureOffset[MGA_AGP_HEAP] = (serverInfo->agpTextureOffset | diff --git a/src/mesa/drivers/dri/mga/mgacontext.h b/src/mesa/drivers/dri/mga/mgacontext.h index 72c1841fedd..1d8c5da6dae 100644 --- a/src/mesa/drivers/dri/mga/mgacontext.h +++ b/src/mesa/drivers/dri/mga/mgacontext.h @@ -29,6 +29,7 @@ #ifndef MGALIB_INC #define MGALIB_INC +#include #include "drm.h" #include "mga_drm.h" #include "dri_util.h" @@ -268,6 +269,8 @@ struct mga_context_t { GLuint swap_count; GLuint swap_missed_count; + uint32_t last_frame_fence; + PFNGLXGETUSTPROC get_ust; /* Drawable, cliprect and scissor information diff --git a/src/mesa/drivers/dri/mga/mgadd.c b/src/mesa/drivers/dri/mga/mgadd.c index 7310641efa3..8532ea95f10 100644 --- a/src/mesa/drivers/dri/mga/mgadd.c +++ b/src/mesa/drivers/dri/mga/mgadd.c @@ -41,7 +41,7 @@ #include "mga_xmesa.h" #include "utils.h" -#define DRIVER_DATE "20030328" +#define DRIVER_DATE "20050609" /*************************************** diff --git a/src/mesa/drivers/dri/mga/mgaioctl.c b/src/mesa/drivers/dri/mga/mgaioctl.c index d741b57cead..62785f6344b 100644 --- a/src/mesa/drivers/dri/mga/mgaioctl.c +++ b/src/mesa/drivers/dri/mga/mgaioctl.c @@ -50,6 +50,49 @@ #include "vblank.h" +int +mgaSetFence( mgaContextPtr mmesa, uint32_t * fence ) +{ + int ret = ENOSYS; + + if ( mmesa->driScreen->drmMinor >= 2 ) { + ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE, + fence, sizeof( uint32_t )); + if (ret) { + fprintf(stderr, "drmMgaSetFence: %d\n", ret); + exit(1); + } + } + + return ret; +} + + +int +mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence ) +{ + int ret = ENOSYS; + + if ( mmesa->driScreen->drmMinor >= 2 ) { + uint32_t temp = fence; + + ret = drmCommandWriteRead( mmesa->driScreen->fd, + DRM_MGA_WAIT_FENCE, + & temp, sizeof( uint32_t )); + if (ret) { + fprintf(stderr, "drmMgaSetFence: %d\n", ret); + exit(1); + } + + if ( curr_fence ) { + *curr_fence = temp; + } + } + + return ret; +} + + static void mga_iload_dma_ioctl(mgaContextPtr mmesa, unsigned long dest, int length) @@ -294,58 +337,64 @@ mgaClear( GLcontext *ctx, GLbitfield mask, GLboolean all, * \bug * The loop in this function should have some sort of a timeout mechanism. * - * \todo - * This routine should be modified to wait on a semaphore. To do this, - * the DRM would have to queue an interrupt when the swap command was - * put in the DMA buffer. When the interrupt occured, the DRM would UP - * the semaphore. This function would then just DOWN the semaphore. + * \warning + * This routine used to assume that the hardware lock was held on entry. It + * now assumes that the lock is \b not held on entry. */ static void mgaWaitForFrameCompletion( mgaContextPtr mmesa ) { - unsigned wait = 0; - const GLuint last_frame = mmesa->sarea->last_frame.head; - const GLuint last_wrap = mmesa->sarea->last_frame.wrap; - - - /* The DMA routines in the kernel track a couple values in the SAREA that - * we use here. The number of times that the primary DMA buffer has - * "wrapped" around is tracked in last_wrap. In addition, the wrap count - * and the buffer position at the end of the last frame are stored in - * last_frame.wrap and last_frame.head. - * - * By comparing the wrap counts and the current DMA pointer value (read - * directly from the hardware) to last_frame.head, we can determine when - * the graphics processor has processed all of the commands for the last - * frame. - * - * In this case "last frame" means the frame of the *previous* swap- - * buffers call. This is done to prevent queuing a second buffer swap - * before the previous swap is executed. - */ - while ( 1 ) { - if ( last_wrap < mmesa->sarea->last_wrap || - ( last_wrap == mmesa->sarea->last_wrap && - last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) - - mmesa->primary_offset) ) ) { - break; - } - if ( 0 ) { - wait++; - fprintf( stderr, " last: head=0x%06x wrap=%d\n", - last_frame, last_wrap ); - fprintf( stderr, " head: head=0x%06lx wrap=%d\n", - (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset), - mmesa->sarea->last_wrap ); - } - UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); + if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) { + unsigned wait = 0; + GLuint last_frame; + GLuint last_wrap; + + + LOCK_HARDWARE( mmesa ); + last_frame = mmesa->sarea->last_frame.head; + last_wrap = mmesa->sarea->last_frame.wrap; + + /* The DMA routines in the kernel track a couple values in the SAREA + * that we use here. The number of times that the primary DMA buffer + * has "wrapped" around is tracked in last_wrap. In addition, the + * wrap count and the buffer position at the end of the last frame are + * stored in last_frame.wrap and last_frame.head. + * + * By comparing the wrap counts and the current DMA pointer value + * (read directly from the hardware) to last_frame.head, we can + * determine when the graphics processor has processed all of the + * commands for the last frame. + * + * In this case "last frame" means the frame of the *previous* swap- + * buffers call. This is done to prevent queuing a second buffer swap + * before the previous swap is executed. + */ + while ( 1 ) { + if ( last_wrap < mmesa->sarea->last_wrap || + ( last_wrap == mmesa->sarea->last_wrap && + last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) - + mmesa->primary_offset) ) ) { + break; + } + if ( 0 ) { + wait++; + fprintf( stderr, " last: head=0x%06x wrap=%d\n", + last_frame, last_wrap ); + fprintf( stderr, " head: head=0x%06lx wrap=%d\n", + (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset), + mmesa->sarea->last_wrap ); + } + UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); - UNLOCK_HARDWARE( mmesa ); - DO_USLEEP( 1 ); - LOCK_HARDWARE( mmesa ); - } - if ( wait ) - fprintf( stderr, "\n" ); + UNLOCK_HARDWARE( mmesa ); + DO_USLEEP( 1 ); + LOCK_HARDWARE( mmesa ); + } + if ( wait ) + fprintf( stderr, "\n" ); + + UNLOCK_HARDWARE( mmesa ); + } } @@ -370,9 +419,7 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv ) FLUSH_BATCH( mmesa ); - LOCK_HARDWARE( mmesa ); mgaWaitForFrameCompletion( mmesa ); - UNLOCK_HARDWARE( mmesa ); driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags, & missed_target ); if ( missed_target ) { @@ -410,6 +457,7 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv ) } } + (void) mgaSetFence( mmesa, & mmesa->last_frame_fence ); UNLOCK_HARDWARE( mmesa ); mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; @@ -425,17 +473,12 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv ) * * \param ctx Context where the \c glFinish command was issued. * - * \todo - * This is overkill. The lock, update-lock, unlock sequence grabs the - * hardware, waits for \b all hardware activity to finish, then releases the - * hardware. A better way would be to flush the pending DMA buffers, emit - * a SOFTRAP, and wait for the SOFTRAP. - * * \sa glFinish, mgaFlush, mgaFlushDMA */ static void mgaFinish( GLcontext *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); + uint32_t fence; LOCK_HARDWARE( mmesa ); @@ -443,12 +486,18 @@ static void mgaFinish( GLcontext *ctx ) mgaFlushVerticesLocked( mmesa ); } - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) { - fprintf(stderr, "mgaRegetLockQuiescent\n"); + if ( mgaSetFence( mmesa, & fence ) == 0 ) { + UNLOCK_HARDWARE( mmesa ); + (void) mgaWaitFence( mmesa, fence, NULL ); } + else { + if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) { + fprintf(stderr, "mgaRegetLockQuiescent\n"); + } - UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH ); - UNLOCK_HARDWARE( mmesa ); + UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH ); + UNLOCK_HARDWARE( mmesa ); + } } -- 2.30.2