i810_accel.c revision 03b705cf
1 2/************************************************************************** 3 4Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 5All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sub license, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice (including the 16next paragraph) shall be included in all copies or substantial portions 17of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33/* 34 * Authors: 35 * Keith Whitwell <keith@tungstengraphics.com> 36 * 37 */ 38 39#include "xf86.h" 40#include "xaarop.h" 41#include "i810.h" 42 43const int I810CopyROP[16] = { 44 ROP_0, /* GXclear */ 45 ROP_DSa, /* GXand */ 46 ROP_SDna, /* GXandReverse */ 47 ROP_S, /* GXcopy */ 48 ROP_DSna, /* GXandInverted */ 49 ROP_D, /* GXnoop */ 50 ROP_DSx, /* GXxor */ 51 ROP_DSo, /* GXor */ 52 ROP_DSon, /* GXnor */ 53 ROP_DSxn, /* GXequiv */ 54 ROP_Dn, /* GXinvert */ 55 ROP_SDno, /* GXorReverse */ 56 ROP_Sn, /* GXcopyInverted */ 57 ROP_DSno, /* GXorInverted */ 58 ROP_DSan, /* GXnand */ 59 ROP_1 /* GXset */ 60}; 61 62const int I810PatternROP[16] = { 63 ROP_0, 64 ROP_DPa, 65 ROP_PDna, 66 ROP_P, 67 ROP_DPna, 68 ROP_D, 69 ROP_DPx, 70 ROP_DPo, 71 ROP_DPon, 72 ROP_PDxn, 73 ROP_Dn, 74 ROP_PDno, 75 ROP_Pn, 76 ROP_DPno, 77 ROP_DPan, 78 ROP_1 79}; 80 81int 82I810WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) 83{ 84 I810Ptr pI810 = I810PTR(pScrn); 85 I810RingBuffer *ring = pI810->LpRing; 86 int iters = 0; 87 int start = 0; 88 int now = 0; 89 int last_head = 0; 90 int first = 0; 91 92 /* If your system hasn't moved the head pointer in 2 seconds, I'm going to 93 * call it crashed. 94 */ 95 if (timeout_millis == 0) 96 timeout_millis = 2000; 97 98 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 99 ErrorF("I810WaitLpRing %d\n", n); 100 first = GetTimeInMillis(); 101 } 102 103 while (ring->space < n) { 104 ring->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 105 ring->space = ring->head - (ring->tail + 8); 106 107 if (ring->space < 0) 108 ring->space += ring->mem.Size; 109 110 iters++; 111 now = GetTimeInMillis(); 112 if (start == 0 || now < start || ring->head != last_head) { 113 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 114 if (now > start) 115 ErrorF("space: %d wanted %d\n", ring->space, n); 116 start = now; 117 last_head = ring->head; 118 } else if (now - start > timeout_millis) { 119 ErrorF("Error in I810WaitLpRing(), now is %d, start is %d\n", now, 120 start); 121 I810PrintErrorState(pScrn); 122 ErrorF("space: %d wanted %d\n", ring->space, n); 123#ifdef HAVE_DRI1 124 if (pI810->directRenderingEnabled) { 125 DRIUnlock(xf86ScrnToScreen(pScrn)); 126 DRICloseScreen(xf86ScrnToScreen(pScrn)); 127 } 128#endif 129#if HAVE_XAA_H 130 pI810->AccelInfoRec = NULL; /* Stops recursive behavior */ 131#endif 132 FatalError("lockup\n"); 133 } 134 135 DELAY(10000); 136 } 137 138 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 139 now = GetTimeInMillis(); 140 if (now - first) { 141 ErrorF("Elapsed %d ms\n", now - first); 142 ErrorF("space: %d wanted %d\n", ring->space, n); 143 } 144 } 145 146 return iters; 147} 148 149void 150I810Sync(ScrnInfoPtr pScrn) 151{ 152 I810Ptr pI810 = I810PTR(pScrn); 153 154 if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) 155 ErrorF("I810Sync\n"); 156 157#ifdef HAVE_DRI1 158 /* VT switching tries to do this. 159 */ 160 if (!pI810->LockHeld && pI810->directRenderingEnabled) { 161 return; 162 } 163#endif 164 165 /* Send a flush instruction and then wait till the ring is empty. 166 * This is stronger than waiting for the blitter to finish as it also 167 * flushes the internal graphics caches. 168 */ 169 { 170 BEGIN_LP_RING(2); 171 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 172 OUT_RING(0); /* pad to quadword */ 173 ADVANCE_LP_RING(); 174 } 175 176 I810WaitLpRing(pScrn, pI810->LpRing->mem.Size - 8, 0); 177 178 pI810->LpRing->space = pI810->LpRing->mem.Size - 8; 179 pI810->nextColorExpandBuf = 0; 180} 181 182void 183I810SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, 184 unsigned int planemask) 185{ 186 I810Ptr pI810 = I810PTR(pScrn); 187 188 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 189 ErrorF("I810SetupForFillRectSolid color: %x rop: %x mask: %x\n", 190 color, rop, planemask); 191 192 /* Color blit, p166 */ 193 pI810->BR[13] = (BR13_SOLID_PATTERN | 194 (I810PatternROP[rop] << 16) | 195 (pScrn->displayWidth * pI810->cpp)); 196 pI810->BR[16] = color; 197} 198 199void 200I810SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) 201{ 202 I810Ptr pI810 = I810PTR(pScrn); 203 204 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 205 ErrorF("I810SubsequentFillRectSolid %d,%d %dx%d\n", x, y, w, h); 206 207 { 208 BEGIN_LP_RING(6); 209 210 OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3); 211 OUT_RING(pI810->BR[13]); 212 OUT_RING((h << 16) | (w * pI810->cpp)); 213 OUT_RING(pI810->bufferOffset + 214 (y * pScrn->displayWidth + x) * pI810->cpp); 215 216 OUT_RING(pI810->BR[16]); 217 OUT_RING(0); /* pad to quadword */ 218 219 ADVANCE_LP_RING(); 220 } 221} 222 223void 224I810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, 225 unsigned int planemask, int transparency_color) 226{ 227 I810Ptr pI810 = I810PTR(pScrn); 228 229 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 230 ErrorF("I810SetupForScreenToScreenCopy %d %d %x %x %d\n", 231 xdir, ydir, rop, planemask, transparency_color); 232 233 pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); 234 235 if (ydir == -1) 236 pI810->BR[13] = (-pI810->BR[13]) & 0xFFFF; 237 if (xdir == -1) 238 pI810->BR[13] |= BR13_RIGHT_TO_LEFT; 239 240 pI810->BR[13] |= I810CopyROP[rop] << 16; 241 242 pI810->BR[18] = 0; 243} 244 245void 246I810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, 247 int x2, int y2, int w, int h) 248{ 249 I810Ptr pI810 = I810PTR(pScrn); 250 int src, dst; 251 int w_back = w; 252 253 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 254 ErrorF( "I810SubsequentScreenToScreenCopy %d,%d - %d,%d %dx%d\n", 255 x1,y1,x2,y2,w,h); 256 /* 257 * This works around a bug in the i810 drawing engine. 258 * This was developed empirically so it may not catch all 259 * cases. 260 */ 261#define I810_MWIDTH 8 262 263 if ( !(pI810->BR[13] & BR13_RIGHT_TO_LEFT) && (y2 - y1) < 3 264 && (y2 - y1) >= 0 && (x2 - x1) <= (w + I810_MWIDTH) 265 && (w > I810_MWIDTH)) 266 w = I810_MWIDTH; 267 do { 268 269 if (pI810->BR[13] & BR13_PITCH_SIGN_BIT) { 270 src = (y1 + h - 1) * pScrn->displayWidth * pI810->cpp; 271 dst = (y2 + h - 1) * pScrn->displayWidth * pI810->cpp; 272 } else { 273 src = y1 * pScrn->displayWidth * pI810->cpp; 274 dst = y2 * pScrn->displayWidth * pI810->cpp; 275 } 276 277 if (pI810->BR[13] & BR13_RIGHT_TO_LEFT) { 278 src += (x1 + w - 1) * pI810->cpp + pI810->cpp - 1; 279 dst += (x2 + w - 1) * pI810->cpp + pI810->cpp - 1; 280 } else { 281 src += x1 * pI810->cpp; 282 dst += x2 * pI810->cpp; 283 } 284 285 286 /* SRC_COPY_BLT, p169 */ 287 { 288 BEGIN_LP_RING(6); 289 OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); 290 OUT_RING( pI810->BR[13]); 291 292 OUT_RING( (h << 16) | (w * pI810->cpp)); 293 OUT_RING( pI810->bufferOffset + dst); 294 295 OUT_RING( pI810->BR[13] & 0xFFFF); 296 OUT_RING( pI810->bufferOffset + src); 297 ADVANCE_LP_RING(); 298 } 299 w_back -= w; 300 if (w_back <= 0) 301 break; 302 x2 += w; 303 x1 += w; 304 if (w_back > I810_MWIDTH) 305 w = I810_MWIDTH; 306 else 307 w = w_back; 308 } while (1); 309} 310 311void 312I810EmitFlush(ScrnInfoPtr pScrn) 313{ 314 I810Ptr pI810 = I810PTR(pScrn); 315 316 BEGIN_LP_RING(2); 317 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 318 OUT_RING(0); 319 ADVANCE_LP_RING(); 320} 321 322void 323I810SelectBuffer(ScrnInfoPtr pScrn, int buffer) 324{ 325 I810Ptr pI810 = I810PTR(pScrn); 326 327 switch (buffer) { 328 case I810_SELECT_BACK: 329 pI810->bufferOffset = pI810->BackBuffer.Start; 330 break; 331 case I810_SELECT_DEPTH: 332 pI810->bufferOffset = pI810->DepthBuffer.Start; 333 break; 334 default: 335 case I810_SELECT_FRONT: 336 pI810->bufferOffset = pI810->FrontBuffer.Start; 337 break; 338 } 339 340 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 341 ErrorF("I810SelectBuffer %d --> offset %x\n", 342 buffer, pI810->bufferOffset); 343} 344 345void 346I810RefreshRing(ScrnInfoPtr pScrn) 347{ 348 I810Ptr pI810 = I810PTR(pScrn); 349 350 pI810->LpRing->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 351 pI810->LpRing->tail = INREG(LP_RING + RING_TAIL); 352 pI810->LpRing->space = pI810->LpRing->head - (pI810->LpRing->tail + 8); 353 if (pI810->LpRing->space < 0) 354 pI810->LpRing->space += pI810->LpRing->mem.Size; 355 356#if HAVE_XAA_H 357 if (pI810->AccelInfoRec) 358 pI810->AccelInfoRec->NeedToSync = TRUE; 359#endif 360} 361