1 
2 /**************************************************************************
3 
4 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5 All Rights Reserved.
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
17 of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE 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 
44 const 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 
63 const 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 
82 int
I810WaitLpRing(ScrnInfoPtr pScrn,int n,int timeout_millis)83 I810WaitLpRing(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 
150 void
I810Sync(ScrnInfoPtr pScrn)151 I810Sync(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 
183 void
I810SetupForSolidFill(ScrnInfoPtr pScrn,int color,int rop,unsigned int planemask)184 I810SetupForSolidFill(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 
200 void
I810SubsequentSolidFillRect(ScrnInfoPtr pScrn,int x,int y,int w,int h)201 I810SubsequentSolidFillRect(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 
224 void
I810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn,int xdir,int ydir,int rop,unsigned int planemask,int transparency_color)225 I810SetupForScreenToScreenCopy(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 
246 void
I810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn,int x1,int y1,int x2,int y2,int w,int h)247 I810SubsequentScreenToScreenCopy(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 
312 void
I810EmitFlush(ScrnInfoPtr pScrn)313 I810EmitFlush(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 
323 void
I810SelectBuffer(ScrnInfoPtr pScrn,int buffer)324 I810SelectBuffer(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 
346 void
I810RefreshRing(ScrnInfoPtr pScrn)347 I810RefreshRing(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