#include /* for usleep() */ #include "main/glheader.h" #include "main/mtypes.h" #include "main/macros.h" #include "main/dd.h" #include "swrast/swrast.h" #include "main/mm.h" #include "i810screen.h" #include "i810_dri.h" #include "main/context.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( struct gl_context *ctx, GLbitfield mask ) { i810ContextPtr imesa = I810_CONTEXT( ctx ); __DRIdrawable *dPriv = imesa->driDrawable; const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask[0]); 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 __DRIdrawable *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 __DRIdrawable *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( struct gl_context *ctx ) { i810ContextPtr imesa = I810_CONTEXT( ctx ); I810_FIREVERTICES( imesa ); } static void i810Finish( struct gl_context *ctx ) { i810ContextPtr imesa = I810_CONTEXT( ctx ); i810DmaFinish( imesa ); } void i810InitIoctlFuncs( struct dd_function_table *functions ) { functions->Flush = i810Flush; functions->Clear = i810Clear; functions->Finish = i810Finish; }