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