diff options
Diffstat (limited to 'src/mesa/drivers/dri/i810/i810ioctl.c')
-rw-r--r-- | src/mesa/drivers/dri/i810/i810ioctl.c | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i810/i810ioctl.c b/src/mesa/drivers/dri/i810/i810ioctl.c new file mode 100644 index 00000000000..d769d58d566 --- /dev/null +++ b/src/mesa/drivers/dri/i810/i810ioctl.c @@ -0,0 +1,510 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/i810/i810ioctl.c,v 1.7 2002/10/30 12:51:33 alanh Exp $ */ + +#include <unistd.h> /* for usleep() */ + +#include "glheader.h" +#include "mtypes.h" +#include "macros.h" +#include "dd.h" +#include "swrast/swrast.h" +#include "mm.h" + +#include "i810screen.h" +#include "i810_dri.h" + +#include "i810context.h" +#include "i810ioctl.h" +#include "i810state.h" + +static drmBufPtr i810_get_buffer_ioctl( i810ContextPtr imesa ) +{ + drmI810DMA dma; + drmBufPtr buf; + int retcode, i = 0; + + while (1) { + retcode = drmCommandWriteRead(imesa->driFd, DRM_I810_GETBUF, + &dma, sizeof(drmI810DMA)); + + if (dma.granted == 1 && retcode == 0) + break; + + if (++i > 1000) { + drmCommandNone(imesa->driFd, DRM_I810_FLUSH); + i = 0; + } + } + + buf = &(imesa->i810Screen->bufs->list[dma.request_idx]); + buf->idx = dma.request_idx; + buf->used = 0; + buf->total = dma.request_size; + buf->address = (drmAddress)dma.virtual; + + return buf; +} + + + +#define DEPTH_SCALE ((1<<16)-1) + +static void i810Clear( GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch ) +{ + i810ContextPtr imesa = I810_CONTEXT( ctx ); + __DRIdrawablePrivate *dPriv = imesa->driDrawable; + const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask); + drmI810Clear clear; + int i; + + clear.flags = 0; + clear.clear_color = imesa->ClearColor; + clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE); + + I810_FIREVERTICES( imesa ); + + if ((mask & DD_FRONT_LEFT_BIT) && colorMask == ~0) { + clear.flags |= I810_FRONT; + mask &= ~DD_FRONT_LEFT_BIT; + } + + if ((mask & DD_BACK_LEFT_BIT) && colorMask == ~0) { + clear.flags |= I810_BACK; + mask &= ~DD_BACK_LEFT_BIT; + } + + if (mask & DD_DEPTH_BIT) { + if (ctx->Depth.Mask) + clear.flags |= I810_DEPTH; + mask &= ~DD_DEPTH_BIT; + } + + if (clear.flags) { + LOCK_HARDWARE( imesa ); + + /* flip top to bottom */ + cy = dPriv->h-cy-ch; + cx += imesa->drawX; + cy += imesa->drawY; + + for (i = 0 ; i < imesa->numClipRects ; ) + { + int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, imesa->numClipRects); + XF86DRIClipRectPtr box = imesa->pClipRects; + XF86DRIClipRectPtr b = imesa->sarea->boxes; + int n = 0; + + if (!all) { + for ( ; i < nr ; i++) { + GLint x = box[i].x1; + GLint y = box[i].y1; + GLint w = box[i].x2 - x; + GLint h = box[i].y2 - y; + + if (x < cx) w -= cx - x, x = cx; + if (y < cy) h -= cy - y, y = cy; + if (x + w > cx + cw) w = cx + cw - x; + if (y + h > cy + ch) h = cy + ch - y; + if (w <= 0) continue; + if (h <= 0) continue; + + b->x1 = x; + b->y1 = y; + b->x2 = x + w; + b->y2 = y + h; + b++; + n++; + } + } else { + for ( ; i < nr ; i++) { + *b++ = *(XF86DRIClipRectPtr)&box[i]; + n++; + } + } + + imesa->sarea->nbox = n; + drmCommandWrite(imesa->driFd, DRM_I810_CLEAR, + &clear, sizeof(drmI810Clear)); + } + + UNLOCK_HARDWARE( imesa ); + imesa->upload_cliprects = GL_TRUE; + } + + if (mask) + _swrast_Clear( ctx, mask, all, cx, cy, cw, ch ); +} + + + + +/* + * Copy the back buffer to the front buffer. + */ +void i810CopyBuffer( const __DRIdrawablePrivate *dPriv ) +{ + i810ContextPtr imesa; + XF86DRIClipRectPtr pbox; + int nbox, i, tmp; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate; + + I810_FIREVERTICES( imesa ); + LOCK_HARDWARE( imesa ); + + pbox = dPriv->pClipRects; + nbox = dPriv->numClipRects; + + for (i = 0 ; i < nbox ; ) + { + int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, dPriv->numClipRects); + XF86DRIClipRectRec *b = (XF86DRIClipRectRec *)imesa->sarea->boxes; + + imesa->sarea->nbox = nr - i; + + for ( ; i < nr ; i++) + *b++ = pbox[i]; + + drmCommandNone(imesa->driFd, DRM_I810_SWAP); + } + + tmp = GET_ENQUEUE_AGE(imesa); + UNLOCK_HARDWARE( imesa ); + + /* multiarb will suck the life out of the server without this throttle: + */ + if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) { + i810WaitAge(imesa, imesa->lastSwap); + } + + imesa->lastSwap = tmp; + imesa->upload_cliprects = GL_TRUE; +} + + +/* + * XXX implement when full-screen extension is done. + */ +void i810PageFlip( const __DRIdrawablePrivate *dPriv ) +{ + i810ContextPtr imesa; + int tmp, ret; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate; + + I810_FIREVERTICES( imesa ); + LOCK_HARDWARE( imesa ); + + if (dPriv->pClipRects) { + *(XF86DRIClipRectRec *)imesa->sarea->boxes = dPriv->pClipRects[0]; + imesa->sarea->nbox = 1; + } + ret = drmCommandNone(imesa->driFd, DRM_I810_FLIP); + if (ret) { + fprintf(stderr, "%s: %d\n", __FUNCTION__, ret); + UNLOCK_HARDWARE( imesa ); + exit(1); + } + + tmp = GET_ENQUEUE_AGE(imesa); + UNLOCK_HARDWARE( imesa ); + + /* multiarb will suck the life out of the server without this throttle: + */ + if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) { + i810WaitAge(imesa, imesa->lastSwap); + } + + /* i810SetDrawBuffer( imesa->glCtx, imesa->glCtx->Color.DriverDrawBuffer );*/ + i810DrawBuffer( imesa->glCtx, imesa->glCtx->Color.DrawBuffer ); + imesa->upload_cliprects = GL_TRUE; + imesa->lastSwap = tmp; + return; +} + + +/* This waits for *everybody* to finish rendering -- overkill. + */ +void i810DmaFinish( i810ContextPtr imesa ) +{ + I810_FIREVERTICES( imesa ); + + LOCK_HARDWARE( imesa ); + i810RegetLockQuiescent( imesa ); + UNLOCK_HARDWARE( imesa ); +} + + +void i810RegetLockQuiescent( i810ContextPtr imesa ) +{ + drmUnlock(imesa->driFd, imesa->hHWContext); + i810GetLock( imesa, DRM_LOCK_QUIESCENT ); +} + +void i810WaitAgeLocked( i810ContextPtr imesa, int age ) +{ + int i = 0, j; + + while (++i < 5000) { + drmCommandNone(imesa->driFd, DRM_I810_GETAGE); + if (GET_DISPATCH_AGE(imesa) >= age) + return; + for (j = 0 ; j < 1000 ; j++) + ; + } + + drmCommandNone(imesa->driFd, DRM_I810_FLUSH); +} + + +void i810WaitAge( i810ContextPtr imesa, int age ) +{ + int i = 0, j; + + while (++i < 5000) { + drmCommandNone(imesa->driFd, DRM_I810_GETAGE); + if (GET_DISPATCH_AGE(imesa) >= age) + return; + for (j = 0 ; j < 1000 ; j++) + ; + } + + i = 0; + while (++i < 1000) { + drmCommandNone(imesa->driFd, DRM_I810_GETAGE); + if (GET_DISPATCH_AGE(imesa) >= age) + return; + usleep(1000); + } + + LOCK_HARDWARE(imesa); + drmCommandNone(imesa->driFd, DRM_I810_FLUSH); + UNLOCK_HARDWARE(imesa); +} + + + + +static int intersect_rect( XF86DRIClipRectPtr out, + XF86DRIClipRectPtr a, + XF86DRIClipRectPtr b ) +{ + *out = *a; + if (b->x1 > out->x1) out->x1 = b->x1; + if (b->x2 < out->x2) out->x2 = b->x2; + if (out->x1 >= out->x2) return 0; + + if (b->y1 > out->y1) out->y1 = b->y1; + if (b->y2 < out->y2) out->y2 = b->y2; + if (out->y1 >= out->y2) return 0; + return 1; +} + + +static void emit_state( i810ContextPtr imesa ) +{ + GLuint dirty = imesa->dirty; + I810SAREAPtr sarea = imesa->sarea; + + if (dirty & I810_UPLOAD_BUFFERS) { + memcpy( sarea->BufferState, imesa->BufferSetup, + sizeof(imesa->BufferSetup) ); + } + + if (dirty & I810_UPLOAD_CTX) { + memcpy( sarea->ContextState, imesa->Setup, + sizeof(imesa->Setup) ); + } + + if (dirty & I810_UPLOAD_TEX0) { + memcpy(sarea->TexState[0], + imesa->CurrentTexObj[0]->Setup, + sizeof(imesa->CurrentTexObj[0]->Setup)); + } + + if (dirty & I810_UPLOAD_TEX1) { + GLuint *setup = sarea->TexState[1]; + + memcpy( setup, + imesa->CurrentTexObj[1]->Setup, + sizeof(imesa->CurrentTexObj[1]->Setup)); + + /* Need this for the case where both units are bound to the same + * texobj. + */ + setup[I810_TEXREG_MI1] ^= (MI1_MAP_0 ^ MI1_MAP_1); + setup[I810_TEXREG_MLC] ^= (MLC_MAP_0 ^ MLC_MAP_1); + setup[I810_TEXREG_MLL] ^= (MLL_MAP_0 ^ MLL_MAP_1); + setup[I810_TEXREG_MCS] ^= (MCS_COORD_0 ^ MCS_COORD_1); + setup[I810_TEXREG_MF] ^= (MF_MAP_0 ^ MF_MAP_1); + } + + sarea->dirty = dirty; + imesa->dirty = 0; +} + + +static void age_imesa( i810ContextPtr imesa, int age ) +{ + if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->base.timestamp = age; + if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->base.timestamp = age; +} + + +void i810FlushPrimsLocked( i810ContextPtr imesa ) +{ + XF86DRIClipRectPtr pbox = (XF86DRIClipRectPtr)imesa->pClipRects; + int nbox = imesa->numClipRects; + drmBufPtr buffer = imesa->vertex_buffer; + I810SAREAPtr sarea = imesa->sarea; + drmI810Vertex vertex; + int i; + + if (I810_DEBUG & DEBUG_STATE) + i810PrintDirty( __FUNCTION__, imesa->dirty ); + + if (imesa->dirty) + emit_state( imesa ); + + vertex.idx = buffer->idx; + vertex.used = imesa->vertex_low; + vertex.discard = 0; + sarea->vertex_prim = imesa->hw_primitive; + + if (!nbox) { + vertex.used = 0; + } + else if (nbox > I810_NR_SAREA_CLIPRECTS) { + imesa->upload_cliprects = GL_TRUE; + } + + if (!nbox || !imesa->upload_cliprects) + { + if (nbox == 1) + sarea->nbox = 0; + else + sarea->nbox = nbox; + + vertex.discard = 1; + drmCommandWrite(imesa->driFd, DRM_I810_VERTEX, + &vertex, sizeof(drmI810Vertex)); + age_imesa(imesa, sarea->last_enqueue); + } + else + { + for (i = 0 ; i < nbox ; ) + { + int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, nbox); + XF86DRIClipRectPtr b = sarea->boxes; + + if (imesa->scissor) { + sarea->nbox = 0; + + for ( ; i < nr ; i++) { + b->x1 = pbox[i].x1 - imesa->drawX; + b->y1 = pbox[i].y1 - imesa->drawY; + b->x2 = pbox[i].x2 - imesa->drawX; + b->y2 = pbox[i].y2 - imesa->drawY; + + if (intersect_rect(b, b, &imesa->scissor_rect)) { + sarea->nbox++; + b++; + } + } + + /* Culled? + */ + if (!sarea->nbox) { + if (nr < nbox) continue; + vertex.used = 0; + } + } else { + sarea->nbox = nr - i; + for ( ; i < nr ; i++, b++) { + b->x1 = pbox[i].x1 - imesa->drawX; + b->y1 = pbox[i].y1 - imesa->drawY; + b->x2 = pbox[i].x2 - imesa->drawX; + b->y2 = pbox[i].y2 - imesa->drawY; + } + } + + /* Finished with the buffer? + */ + if (nr == nbox) + vertex.discard = 1; + + drmCommandWrite(imesa->driFd, DRM_I810_VERTEX, + &vertex, sizeof(drmI810Vertex)); + age_imesa(imesa, imesa->sarea->last_enqueue); + } + } + + /* Reset imesa vars: + */ + imesa->vertex_buffer = 0; + imesa->vertex_addr = 0; + imesa->vertex_low = 0; + imesa->vertex_high = 0; + imesa->vertex_last_prim = 0; + imesa->dirty = 0; + imesa->upload_cliprects = GL_FALSE; +} + +void i810FlushPrimsGetBuffer( i810ContextPtr imesa ) +{ + LOCK_HARDWARE(imesa); + + if (imesa->vertex_buffer) + i810FlushPrimsLocked( imesa ); + + imesa->vertex_buffer = i810_get_buffer_ioctl( imesa ); + imesa->vertex_high = imesa->vertex_buffer->total; + imesa->vertex_addr = (char *)imesa->vertex_buffer->address; + imesa->vertex_low = 4; /* leave room for instruction header */ + imesa->vertex_last_prim = imesa->vertex_low; + UNLOCK_HARDWARE(imesa); +} + + +void i810FlushPrims( i810ContextPtr imesa ) +{ + if (imesa->vertex_buffer) { + LOCK_HARDWARE( imesa ); + i810FlushPrimsLocked( imesa ); + UNLOCK_HARDWARE( imesa ); + } +} + + + +int i810_check_copy(int fd) +{ + return(drmCommandNone(fd, DRM_I810_DOCOPY)); +} + +static void i810Flush( GLcontext *ctx ) +{ + i810ContextPtr imesa = I810_CONTEXT( ctx ); + I810_FIREVERTICES( imesa ); +} + +static void i810Finish( GLcontext *ctx ) +{ + i810ContextPtr imesa = I810_CONTEXT( ctx ); + i810DmaFinish( imesa ); +} + +void i810InitIoctlFuncs( GLcontext *ctx ) +{ + ctx->Driver.Flush = i810Flush; + ctx->Driver.Clear = i810Clear; + ctx->Driver.Finish = i810Finish; +} |