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