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