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