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 "xorg-server.h" 40#include "xf86.h" 41#include "xaarop.h" 42#include "i810.h" 43 44const int I810CopyROP[16] = { 45 ROP_0, /* GXclear */ 46 ROP_DSa, /* GXand */ 47 ROP_SDna, /* GXandReverse */ 48 ROP_S, /* GXcopy */ 49 ROP_DSna, /* GXandInverted */ 50 ROP_D, /* GXnoop */ 51 ROP_DSx, /* GXxor */ 52 ROP_DSo, /* GXor */ 53 ROP_DSon, /* GXnor */ 54 ROP_DSxn, /* GXequiv */ 55 ROP_Dn, /* GXinvert */ 56 ROP_SDno, /* GXorReverse */ 57 ROP_Sn, /* GXcopyInverted */ 58 ROP_DSno, /* GXorInverted */ 59 ROP_DSan, /* GXnand */ 60 ROP_1 /* GXset */ 61}; 62 63const int I810PatternROP[16] = { 64 ROP_0, 65 ROP_DPa, 66 ROP_PDna, 67 ROP_P, 68 ROP_DPna, 69 ROP_D, 70 ROP_DPx, 71 ROP_DPo, 72 ROP_DPon, 73 ROP_PDxn, 74 ROP_Dn, 75 ROP_PDno, 76 ROP_Pn, 77 ROP_DPno, 78 ROP_DPan, 79 ROP_1 80}; 81 82int 83I810WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) 84{ 85 I810Ptr pI810 = I810PTR(pScrn); 86 I810RingBuffer *ring = pI810->LpRing; 87 int iters = 0; 88 int start = 0; 89 int now = 0; 90 int last_head = 0; 91 int first = 0; 92 93 /* If your system hasn't moved the head pointer in 2 seconds, I'm going to 94 * call it crashed. 95 */ 96 if (timeout_millis == 0) 97 timeout_millis = 2000; 98 99 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 100 ErrorF("I810WaitLpRing %d\n", n); 101 first = GetTimeInMillis(); 102 } 103 104 while (ring->space < n) { 105 ring->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 106 ring->space = ring->head - (ring->tail + 8); 107 108 if (ring->space < 0) 109 ring->space += ring->mem.Size; 110 111 iters++; 112 now = GetTimeInMillis(); 113 if (start == 0 || now < start || ring->head != last_head) { 114 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 115 if (now > start) 116 ErrorF("space: %d wanted %d\n", ring->space, n); 117 start = now; 118 last_head = ring->head; 119 } else if (now - start > timeout_millis) { 120 ErrorF("Error in I810WaitLpRing(), now is %d, start is %d\n", now, 121 start); 122 I810PrintErrorState(pScrn); 123 ErrorF("space: %d wanted %d\n", ring->space, n); 124#ifdef HAVE_DRI1 125 if (pI810->directRenderingEnabled) { 126 DRIUnlock(xf86ScrnToScreen(pScrn)); 127 DRICloseScreen(xf86ScrnToScreen(pScrn)); 128 } 129#endif 130#if HAVE_XAA_H 131 pI810->AccelInfoRec = NULL; /* Stops recursive behavior */ 132#endif 133 FatalError("lockup\n"); 134 } 135 136 DELAY(10000); 137 } 138 139 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 140 now = GetTimeInMillis(); 141 if (now - first) { 142 ErrorF("Elapsed %d ms\n", now - first); 143 ErrorF("space: %d wanted %d\n", ring->space, n); 144 } 145 } 146 147 return iters; 148} 149 150void 151I810Sync(ScrnInfoPtr pScrn) 152{ 153 I810Ptr pI810 = I810PTR(pScrn); 154 155 if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) 156 ErrorF("I810Sync\n"); 157 158#ifdef HAVE_DRI1 159 /* VT switching tries to do this. 160 */ 161 if (!pI810->LockHeld && pI810->directRenderingEnabled) { 162 return; 163 } 164#endif 165 166 /* Send a flush instruction and then wait till the ring is empty. 167 * This is stronger than waiting for the blitter to finish as it also 168 * flushes the internal graphics caches. 169 */ 170 { 171 BEGIN_LP_RING(2); 172 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 173 OUT_RING(0); /* pad to quadword */ 174 ADVANCE_LP_RING(); 175 } 176 177 I810WaitLpRing(pScrn, pI810->LpRing->mem.Size - 8, 0); 178 179 pI810->LpRing->space = pI810->LpRing->mem.Size - 8; 180 pI810->nextColorExpandBuf = 0; 181} 182 183void 184I810SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, 185 unsigned int planemask) 186{ 187 I810Ptr pI810 = I810PTR(pScrn); 188 189 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 190 ErrorF("I810SetupForFillRectSolid color: %x rop: %x mask: %x\n", 191 color, rop, planemask); 192 193 /* Color blit, p166 */ 194 pI810->BR[13] = (BR13_SOLID_PATTERN | 195 (I810PatternROP[rop] << 16) | 196 (pScrn->displayWidth * pI810->cpp)); 197 pI810->BR[16] = color; 198} 199 200void 201I810SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) 202{ 203 I810Ptr pI810 = I810PTR(pScrn); 204 205 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 206 ErrorF("I810SubsequentFillRectSolid %d,%d %dx%d\n", x, y, w, h); 207 208 { 209 BEGIN_LP_RING(6); 210 211 OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3); 212 OUT_RING(pI810->BR[13]); 213 OUT_RING((h << 16) | (w * pI810->cpp)); 214 OUT_RING(pI810->bufferOffset + 215 (y * pScrn->displayWidth + x) * pI810->cpp); 216 217 OUT_RING(pI810->BR[16]); 218 OUT_RING(0); /* pad to quadword */ 219 220 ADVANCE_LP_RING(); 221 } 222} 223 224void 225I810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, 226 unsigned int planemask, int transparency_color) 227{ 228 I810Ptr pI810 = I810PTR(pScrn); 229 230 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 231 ErrorF("I810SetupForScreenToScreenCopy %d %d %x %x %d\n", 232 xdir, ydir, rop, planemask, transparency_color); 233 234 pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); 235 236 if (ydir == -1) 237 pI810->BR[13] = (-pI810->BR[13]) & 0xFFFF; 238 if (xdir == -1) 239 pI810->BR[13] |= BR13_RIGHT_TO_LEFT; 240 241 pI810->BR[13] |= I810CopyROP[rop] << 16; 242 243 pI810->BR[18] = 0; 244} 245 246void 247I810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, 248 int x2, int y2, int w, int h) 249{ 250 I810Ptr pI810 = I810PTR(pScrn); 251 int src, dst; 252 int w_back = w; 253 254 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 255 ErrorF( "I810SubsequentScreenToScreenCopy %d,%d - %d,%d %dx%d\n", 256 x1,y1,x2,y2,w,h); 257 /* 258 * This works around a bug in the i810 drawing engine. 259 * This was developed empirically so it may not catch all 260 * cases. 261 */ 262#define I810_MWIDTH 8 263 264 if ( !(pI810->BR[13] & BR13_RIGHT_TO_LEFT) && (y2 - y1) < 3 265 && (y2 - y1) >= 0 && (x2 - x1) <= (w + I810_MWIDTH) 266 && (w > I810_MWIDTH)) 267 w = I810_MWIDTH; 268 do { 269 270 if (pI810->BR[13] & BR13_PITCH_SIGN_BIT) { 271 src = (y1 + h - 1) * pScrn->displayWidth * pI810->cpp; 272 dst = (y2 + h - 1) * pScrn->displayWidth * pI810->cpp; 273 } else { 274 src = y1 * pScrn->displayWidth * pI810->cpp; 275 dst = y2 * pScrn->displayWidth * pI810->cpp; 276 } 277 278 if (pI810->BR[13] & BR13_RIGHT_TO_LEFT) { 279 src += (x1 + w - 1) * pI810->cpp + pI810->cpp - 1; 280 dst += (x2 + w - 1) * pI810->cpp + pI810->cpp - 1; 281 } else { 282 src += x1 * pI810->cpp; 283 dst += x2 * pI810->cpp; 284 } 285 286 287 /* SRC_COPY_BLT, p169 */ 288 { 289 BEGIN_LP_RING(6); 290 OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); 291 OUT_RING( pI810->BR[13]); 292 293 OUT_RING( (h << 16) | (w * pI810->cpp)); 294 OUT_RING( pI810->bufferOffset + dst); 295 296 OUT_RING( pI810->BR[13] & 0xFFFF); 297 OUT_RING( pI810->bufferOffset + src); 298 ADVANCE_LP_RING(); 299 } 300 w_back -= w; 301 if (w_back <= 0) 302 break; 303 x2 += w; 304 x1 += w; 305 if (w_back > I810_MWIDTH) 306 w = I810_MWIDTH; 307 else 308 w = w_back; 309 } while (1); 310} 311 312void 313I810EmitFlush(ScrnInfoPtr pScrn) 314{ 315 I810Ptr pI810 = I810PTR(pScrn); 316 317 BEGIN_LP_RING(2); 318 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 319 OUT_RING(0); 320 ADVANCE_LP_RING(); 321} 322 323void 324I810SelectBuffer(ScrnInfoPtr pScrn, int buffer) 325{ 326 I810Ptr pI810 = I810PTR(pScrn); 327 328 switch (buffer) { 329 case I810_SELECT_BACK: 330 pI810->bufferOffset = pI810->BackBuffer.Start; 331 break; 332 case I810_SELECT_DEPTH: 333 pI810->bufferOffset = pI810->DepthBuffer.Start; 334 break; 335 default: 336 case I810_SELECT_FRONT: 337 pI810->bufferOffset = pI810->FrontBuffer.Start; 338 break; 339 } 340 341 if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 342 ErrorF("I810SelectBuffer %d --> offset %x\n", 343 buffer, pI810->bufferOffset); 344} 345 346void 347I810RefreshRing(ScrnInfoPtr pScrn) 348{ 349 I810Ptr pI810 = I810PTR(pScrn); 350 351 pI810->LpRing->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 352 pI810->LpRing->tail = INREG(LP_RING + RING_TAIL); 353 pI810->LpRing->space = pI810->LpRing->head - (pI810->LpRing->tail + 8); 354 if (pI810->LpRing->space < 0) 355 pI810->LpRing->space += pI810->LpRing->mem.Size; 356 357#if HAVE_XAA_H 358 if (pI810->AccelInfoRec) 359 pI810->AccelInfoRec->NeedToSync = TRUE; 360#endif 361} 362