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
This commit is contained in:
parent
fb818a0b11
commit
aa26915472
|
@ -31,6 +31,7 @@
|
|||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
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->primary.handle = serverInfo->primary.handle;
|
||||
mgaScreen->primary.size = serverInfo->primary.size;
|
||||
|
||||
|
||||
mgaScreen->textureOffset[MGA_CARD_HEAP] = serverInfo->textureOffset;
|
||||
mgaScreen->textureOffset[MGA_AGP_HEAP] = (serverInfo->agpTextureOffset |
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef MGALIB_INC
|
||||
#define MGALIB_INC
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "mga_xmesa.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define DRIVER_DATE "20030328"
|
||||
#define DRIVER_DATE "20050609"
|
||||
|
||||
|
||||
/***************************************
|
||||
|
|
|
@ -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;
|
||||
if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) {
|
||||
unsigned wait = 0;
|
||||
GLuint last_frame;
|
||||
GLuint last_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 );
|
||||
LOCK_HARDWARE( mmesa );
|
||||
last_frame = mmesa->sarea->last_frame.head;
|
||||
last_wrap = mmesa->sarea->last_frame.wrap;
|
||||
|
||||
UNLOCK_HARDWARE( mmesa );
|
||||
DO_USLEEP( 1 );
|
||||
LOCK_HARDWARE( mmesa );
|
||||
}
|
||||
if ( wait )
|
||||
fprintf( stderr, "\n" );
|
||||
/* 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue