| /* $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 ) |
| { |
| i810ContextPtr imesa = I810_CONTEXT( ctx ); |
| __DRIdrawablePrivate *dPriv = imesa->driDrawable; |
| const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask); |
| drmI810Clear clear; |
| unsigned int i; |
| |
| clear.flags = 0; |
| clear.clear_color = imesa->ClearColor; |
| clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE); |
| |
| I810_FIREVERTICES( imesa ); |
| |
| if ((mask & BUFFER_BIT_FRONT_LEFT) && colorMask == ~0U) { |
| clear.flags |= I810_FRONT; |
| mask &= ~BUFFER_BIT_FRONT_LEFT; |
| } |
| |
| if ((mask & BUFFER_BIT_BACK_LEFT) && colorMask == ~0U) { |
| clear.flags |= I810_BACK; |
| mask &= ~BUFFER_BIT_BACK_LEFT; |
| } |
| |
| if (mask & BUFFER_BIT_DEPTH) { |
| if (ctx->Depth.Mask) |
| clear.flags |= I810_DEPTH; |
| mask &= ~BUFFER_BIT_DEPTH; |
| } |
| |
| if (clear.flags) { |
| GLint cx, cy, cw, ch; |
| |
| LOCK_HARDWARE( imesa ); |
| |
| /* compute region after locking: */ |
| cx = ctx->DrawBuffer->_Xmin; |
| cy = ctx->DrawBuffer->_Ymin; |
| cw = ctx->DrawBuffer->_Xmax - cx; |
| ch = ctx->DrawBuffer->_Ymax - cy; |
| |
| /* flip top to bottom */ |
| cy = dPriv->h-cy-ch; |
| cx += imesa->drawX; |
| cy += imesa->drawY; |
| |
| for (i = 0 ; i < imesa->numClipRects ; ) |
| { |
| unsigned int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, imesa->numClipRects); |
| drm_clip_rect_t *box = imesa->pClipRects; |
| drm_clip_rect_t *b = (drm_clip_rect_t *)imesa->sarea->boxes; |
| int n = 0; |
| |
| if (cw != dPriv->w || ch != dPriv->h) { |
| /* clear sub region */ |
| 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 { |
| /* clear whole buffer */ |
| for ( ; i < nr ; i++) { |
| *b++ = 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 ); |
| } |
| |
| |
| |
| |
| /* |
| * Copy the back buffer to the front buffer. |
| */ |
| void i810CopyBuffer( const __DRIdrawablePrivate *dPriv ) |
| { |
| i810ContextPtr imesa; |
| drm_clip_rect_t *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 = (drm_clip_rect_t *)dPriv->pClipRects; |
| nbox = dPriv->numClipRects; |
| |
| for (i = 0 ; i < nbox ; ) |
| { |
| int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, dPriv->numClipRects); |
| drm_clip_rect_t *b = (drm_clip_rect_t *)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) { |
| memcpy(&(imesa->sarea->boxes[0]), &(dPriv->pClipRects[0]), |
| sizeof(drm_clip_rect_t)); |
| 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[0] ); |
| 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( drm_clip_rect_t *out, |
| drm_clip_rect_t *a, |
| drm_clip_rect_t *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 ) |
| { |
| drm_clip_rect_t *pbox = 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); |
| drm_clip_rect_t *b = (drm_clip_rect_t *)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( struct dd_function_table *functions ) |
| { |
| functions->Flush = i810Flush; |
| functions->Clear = i810Clear; |
| functions->Finish = i810Finish; |
| } |