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