add the i810 driver - no kernel driver yet
[mesa.git] / src / mesa / drivers / dri / i810 / i810ioctl.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/i810/i810ioctl.c,v 1.7 2002/10/30 12:51:33 alanh Exp $ */
2
3 #include <unistd.h> /* for usleep() */
4
5 #include "glheader.h"
6 #include "mtypes.h"
7 #include "macros.h"
8 #include "dd.h"
9 #include "swrast/swrast.h"
10 #include "mm.h"
11
12 #include "i810screen.h"
13 #include "i810_dri.h"
14
15 #include "i810context.h"
16 #include "i810ioctl.h"
17 #include "i810state.h"
18
19 static drmBufPtr i810_get_buffer_ioctl( i810ContextPtr imesa )
20 {
21 drmI810DMA dma;
22 drmBufPtr buf;
23 int retcode, i = 0;
24
25 while (1) {
26 retcode = drmCommandWriteRead(imesa->driFd, DRM_I810_GETBUF,
27 &dma, sizeof(drmI810DMA));
28
29 if (dma.granted == 1 && retcode == 0)
30 break;
31
32 if (++i > 1000) {
33 drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
34 i = 0;
35 }
36 }
37
38 buf = &(imesa->i810Screen->bufs->list[dma.request_idx]);
39 buf->idx = dma.request_idx;
40 buf->used = 0;
41 buf->total = dma.request_size;
42 buf->address = (drmAddress)dma.virtual;
43
44 return buf;
45 }
46
47
48
49 #define DEPTH_SCALE ((1<<16)-1)
50
51 static void i810Clear( GLcontext *ctx, GLbitfield mask, GLboolean all,
52 GLint cx, GLint cy, GLint cw, GLint ch )
53 {
54 i810ContextPtr imesa = I810_CONTEXT( ctx );
55 __DRIdrawablePrivate *dPriv = imesa->driDrawable;
56 const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
57 drmI810Clear clear;
58 int i;
59
60 clear.flags = 0;
61 clear.clear_color = imesa->ClearColor;
62 clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE);
63
64 I810_FIREVERTICES( imesa );
65
66 if ((mask & DD_FRONT_LEFT_BIT) && colorMask == ~0) {
67 clear.flags |= I810_FRONT;
68 mask &= ~DD_FRONT_LEFT_BIT;
69 }
70
71 if ((mask & DD_BACK_LEFT_BIT) && colorMask == ~0) {
72 clear.flags |= I810_BACK;
73 mask &= ~DD_BACK_LEFT_BIT;
74 }
75
76 if (mask & DD_DEPTH_BIT) {
77 if (ctx->Depth.Mask)
78 clear.flags |= I810_DEPTH;
79 mask &= ~DD_DEPTH_BIT;
80 }
81
82 if (clear.flags) {
83 LOCK_HARDWARE( imesa );
84
85 /* flip top to bottom */
86 cy = dPriv->h-cy-ch;
87 cx += imesa->drawX;
88 cy += imesa->drawY;
89
90 for (i = 0 ; i < imesa->numClipRects ; )
91 {
92 int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, imesa->numClipRects);
93 XF86DRIClipRectPtr box = imesa->pClipRects;
94 XF86DRIClipRectPtr b = imesa->sarea->boxes;
95 int n = 0;
96
97 if (!all) {
98 for ( ; i < nr ; i++) {
99 GLint x = box[i].x1;
100 GLint y = box[i].y1;
101 GLint w = box[i].x2 - x;
102 GLint h = box[i].y2 - y;
103
104 if (x < cx) w -= cx - x, x = cx;
105 if (y < cy) h -= cy - y, y = cy;
106 if (x + w > cx + cw) w = cx + cw - x;
107 if (y + h > cy + ch) h = cy + ch - y;
108 if (w <= 0) continue;
109 if (h <= 0) continue;
110
111 b->x1 = x;
112 b->y1 = y;
113 b->x2 = x + w;
114 b->y2 = y + h;
115 b++;
116 n++;
117 }
118 } else {
119 for ( ; i < nr ; i++) {
120 *b++ = *(XF86DRIClipRectPtr)&box[i];
121 n++;
122 }
123 }
124
125 imesa->sarea->nbox = n;
126 drmCommandWrite(imesa->driFd, DRM_I810_CLEAR,
127 &clear, sizeof(drmI810Clear));
128 }
129
130 UNLOCK_HARDWARE( imesa );
131 imesa->upload_cliprects = GL_TRUE;
132 }
133
134 if (mask)
135 _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
136 }
137
138
139
140
141 /*
142 * Copy the back buffer to the front buffer.
143 */
144 void i810CopyBuffer( const __DRIdrawablePrivate *dPriv )
145 {
146 i810ContextPtr imesa;
147 XF86DRIClipRectPtr pbox;
148 int nbox, i, tmp;
149
150 assert(dPriv);
151 assert(dPriv->driContextPriv);
152 assert(dPriv->driContextPriv->driverPrivate);
153
154 imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
155
156 I810_FIREVERTICES( imesa );
157 LOCK_HARDWARE( imesa );
158
159 pbox = dPriv->pClipRects;
160 nbox = dPriv->numClipRects;
161
162 for (i = 0 ; i < nbox ; )
163 {
164 int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
165 XF86DRIClipRectRec *b = (XF86DRIClipRectRec *)imesa->sarea->boxes;
166
167 imesa->sarea->nbox = nr - i;
168
169 for ( ; i < nr ; i++)
170 *b++ = pbox[i];
171
172 drmCommandNone(imesa->driFd, DRM_I810_SWAP);
173 }
174
175 tmp = GET_ENQUEUE_AGE(imesa);
176 UNLOCK_HARDWARE( imesa );
177
178 /* multiarb will suck the life out of the server without this throttle:
179 */
180 if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) {
181 i810WaitAge(imesa, imesa->lastSwap);
182 }
183
184 imesa->lastSwap = tmp;
185 imesa->upload_cliprects = GL_TRUE;
186 }
187
188
189 /*
190 * XXX implement when full-screen extension is done.
191 */
192 void i810PageFlip( const __DRIdrawablePrivate *dPriv )
193 {
194 i810ContextPtr imesa;
195 int tmp, ret;
196
197 assert(dPriv);
198 assert(dPriv->driContextPriv);
199 assert(dPriv->driContextPriv->driverPrivate);
200
201 imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
202
203 I810_FIREVERTICES( imesa );
204 LOCK_HARDWARE( imesa );
205
206 if (dPriv->pClipRects) {
207 *(XF86DRIClipRectRec *)imesa->sarea->boxes = dPriv->pClipRects[0];
208 imesa->sarea->nbox = 1;
209 }
210 ret = drmCommandNone(imesa->driFd, DRM_I810_FLIP);
211 if (ret) {
212 fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
213 UNLOCK_HARDWARE( imesa );
214 exit(1);
215 }
216
217 tmp = GET_ENQUEUE_AGE(imesa);
218 UNLOCK_HARDWARE( imesa );
219
220 /* multiarb will suck the life out of the server without this throttle:
221 */
222 if (GET_DISPATCH_AGE(imesa) < imesa->lastSwap) {
223 i810WaitAge(imesa, imesa->lastSwap);
224 }
225
226 /* i810SetDrawBuffer( imesa->glCtx, imesa->glCtx->Color.DriverDrawBuffer );*/
227 i810DrawBuffer( imesa->glCtx, imesa->glCtx->Color.DrawBuffer );
228 imesa->upload_cliprects = GL_TRUE;
229 imesa->lastSwap = tmp;
230 return;
231 }
232
233
234 /* This waits for *everybody* to finish rendering -- overkill.
235 */
236 void i810DmaFinish( i810ContextPtr imesa )
237 {
238 I810_FIREVERTICES( imesa );
239
240 LOCK_HARDWARE( imesa );
241 i810RegetLockQuiescent( imesa );
242 UNLOCK_HARDWARE( imesa );
243 }
244
245
246 void i810RegetLockQuiescent( i810ContextPtr imesa )
247 {
248 drmUnlock(imesa->driFd, imesa->hHWContext);
249 i810GetLock( imesa, DRM_LOCK_QUIESCENT );
250 }
251
252 void i810WaitAgeLocked( i810ContextPtr imesa, int age )
253 {
254 int i = 0, j;
255
256 while (++i < 5000) {
257 drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
258 if (GET_DISPATCH_AGE(imesa) >= age)
259 return;
260 for (j = 0 ; j < 1000 ; j++)
261 ;
262 }
263
264 drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
265 }
266
267
268 void i810WaitAge( i810ContextPtr imesa, int age )
269 {
270 int i = 0, j;
271
272 while (++i < 5000) {
273 drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
274 if (GET_DISPATCH_AGE(imesa) >= age)
275 return;
276 for (j = 0 ; j < 1000 ; j++)
277 ;
278 }
279
280 i = 0;
281 while (++i < 1000) {
282 drmCommandNone(imesa->driFd, DRM_I810_GETAGE);
283 if (GET_DISPATCH_AGE(imesa) >= age)
284 return;
285 usleep(1000);
286 }
287
288 LOCK_HARDWARE(imesa);
289 drmCommandNone(imesa->driFd, DRM_I810_FLUSH);
290 UNLOCK_HARDWARE(imesa);
291 }
292
293
294
295
296 static int intersect_rect( XF86DRIClipRectPtr out,
297 XF86DRIClipRectPtr a,
298 XF86DRIClipRectPtr b )
299 {
300 *out = *a;
301 if (b->x1 > out->x1) out->x1 = b->x1;
302 if (b->x2 < out->x2) out->x2 = b->x2;
303 if (out->x1 >= out->x2) return 0;
304
305 if (b->y1 > out->y1) out->y1 = b->y1;
306 if (b->y2 < out->y2) out->y2 = b->y2;
307 if (out->y1 >= out->y2) return 0;
308 return 1;
309 }
310
311
312 static void emit_state( i810ContextPtr imesa )
313 {
314 GLuint dirty = imesa->dirty;
315 I810SAREAPtr sarea = imesa->sarea;
316
317 if (dirty & I810_UPLOAD_BUFFERS) {
318 memcpy( sarea->BufferState, imesa->BufferSetup,
319 sizeof(imesa->BufferSetup) );
320 }
321
322 if (dirty & I810_UPLOAD_CTX) {
323 memcpy( sarea->ContextState, imesa->Setup,
324 sizeof(imesa->Setup) );
325 }
326
327 if (dirty & I810_UPLOAD_TEX0) {
328 memcpy(sarea->TexState[0],
329 imesa->CurrentTexObj[0]->Setup,
330 sizeof(imesa->CurrentTexObj[0]->Setup));
331 }
332
333 if (dirty & I810_UPLOAD_TEX1) {
334 GLuint *setup = sarea->TexState[1];
335
336 memcpy( setup,
337 imesa->CurrentTexObj[1]->Setup,
338 sizeof(imesa->CurrentTexObj[1]->Setup));
339
340 /* Need this for the case where both units are bound to the same
341 * texobj.
342 */
343 setup[I810_TEXREG_MI1] ^= (MI1_MAP_0 ^ MI1_MAP_1);
344 setup[I810_TEXREG_MLC] ^= (MLC_MAP_0 ^ MLC_MAP_1);
345 setup[I810_TEXREG_MLL] ^= (MLL_MAP_0 ^ MLL_MAP_1);
346 setup[I810_TEXREG_MCS] ^= (MCS_COORD_0 ^ MCS_COORD_1);
347 setup[I810_TEXREG_MF] ^= (MF_MAP_0 ^ MF_MAP_1);
348 }
349
350 sarea->dirty = dirty;
351 imesa->dirty = 0;
352 }
353
354
355 static void age_imesa( i810ContextPtr imesa, int age )
356 {
357 if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->base.timestamp = age;
358 if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->base.timestamp = age;
359 }
360
361
362 void i810FlushPrimsLocked( i810ContextPtr imesa )
363 {
364 XF86DRIClipRectPtr pbox = (XF86DRIClipRectPtr)imesa->pClipRects;
365 int nbox = imesa->numClipRects;
366 drmBufPtr buffer = imesa->vertex_buffer;
367 I810SAREAPtr sarea = imesa->sarea;
368 drmI810Vertex vertex;
369 int i;
370
371 if (I810_DEBUG & DEBUG_STATE)
372 i810PrintDirty( __FUNCTION__, imesa->dirty );
373
374 if (imesa->dirty)
375 emit_state( imesa );
376
377 vertex.idx = buffer->idx;
378 vertex.used = imesa->vertex_low;
379 vertex.discard = 0;
380 sarea->vertex_prim = imesa->hw_primitive;
381
382 if (!nbox) {
383 vertex.used = 0;
384 }
385 else if (nbox > I810_NR_SAREA_CLIPRECTS) {
386 imesa->upload_cliprects = GL_TRUE;
387 }
388
389 if (!nbox || !imesa->upload_cliprects)
390 {
391 if (nbox == 1)
392 sarea->nbox = 0;
393 else
394 sarea->nbox = nbox;
395
396 vertex.discard = 1;
397 drmCommandWrite(imesa->driFd, DRM_I810_VERTEX,
398 &vertex, sizeof(drmI810Vertex));
399 age_imesa(imesa, sarea->last_enqueue);
400 }
401 else
402 {
403 for (i = 0 ; i < nbox ; )
404 {
405 int nr = MIN2(i + I810_NR_SAREA_CLIPRECTS, nbox);
406 XF86DRIClipRectPtr b = sarea->boxes;
407
408 if (imesa->scissor) {
409 sarea->nbox = 0;
410
411 for ( ; i < nr ; i++) {
412 b->x1 = pbox[i].x1 - imesa->drawX;
413 b->y1 = pbox[i].y1 - imesa->drawY;
414 b->x2 = pbox[i].x2 - imesa->drawX;
415 b->y2 = pbox[i].y2 - imesa->drawY;
416
417 if (intersect_rect(b, b, &imesa->scissor_rect)) {
418 sarea->nbox++;
419 b++;
420 }
421 }
422
423 /* Culled?
424 */
425 if (!sarea->nbox) {
426 if (nr < nbox) continue;
427 vertex.used = 0;
428 }
429 } else {
430 sarea->nbox = nr - i;
431 for ( ; i < nr ; i++, b++) {
432 b->x1 = pbox[i].x1 - imesa->drawX;
433 b->y1 = pbox[i].y1 - imesa->drawY;
434 b->x2 = pbox[i].x2 - imesa->drawX;
435 b->y2 = pbox[i].y2 - imesa->drawY;
436 }
437 }
438
439 /* Finished with the buffer?
440 */
441 if (nr == nbox)
442 vertex.discard = 1;
443
444 drmCommandWrite(imesa->driFd, DRM_I810_VERTEX,
445 &vertex, sizeof(drmI810Vertex));
446 age_imesa(imesa, imesa->sarea->last_enqueue);
447 }
448 }
449
450 /* Reset imesa vars:
451 */
452 imesa->vertex_buffer = 0;
453 imesa->vertex_addr = 0;
454 imesa->vertex_low = 0;
455 imesa->vertex_high = 0;
456 imesa->vertex_last_prim = 0;
457 imesa->dirty = 0;
458 imesa->upload_cliprects = GL_FALSE;
459 }
460
461 void i810FlushPrimsGetBuffer( i810ContextPtr imesa )
462 {
463 LOCK_HARDWARE(imesa);
464
465 if (imesa->vertex_buffer)
466 i810FlushPrimsLocked( imesa );
467
468 imesa->vertex_buffer = i810_get_buffer_ioctl( imesa );
469 imesa->vertex_high = imesa->vertex_buffer->total;
470 imesa->vertex_addr = (char *)imesa->vertex_buffer->address;
471 imesa->vertex_low = 4; /* leave room for instruction header */
472 imesa->vertex_last_prim = imesa->vertex_low;
473 UNLOCK_HARDWARE(imesa);
474 }
475
476
477 void i810FlushPrims( i810ContextPtr imesa )
478 {
479 if (imesa->vertex_buffer) {
480 LOCK_HARDWARE( imesa );
481 i810FlushPrimsLocked( imesa );
482 UNLOCK_HARDWARE( imesa );
483 }
484 }
485
486
487
488 int i810_check_copy(int fd)
489 {
490 return(drmCommandNone(fd, DRM_I810_DOCOPY));
491 }
492
493 static void i810Flush( GLcontext *ctx )
494 {
495 i810ContextPtr imesa = I810_CONTEXT( ctx );
496 I810_FIREVERTICES( imesa );
497 }
498
499 static void i810Finish( GLcontext *ctx )
500 {
501 i810ContextPtr imesa = I810_CONTEXT( ctx );
502 i810DmaFinish( imesa );
503 }
504
505 void i810InitIoctlFuncs( GLcontext *ctx )
506 {
507 ctx->Driver.Flush = i810Flush;
508 ctx->Driver.Clear = i810Clear;
509 ctx->Driver.Finish = i810Finish;
510 }