Fixed off by one errors in clipping.
[mesa.git] / src / mesa / drivers / dri / mga / mgaioctl.c
1 /*
2 * Copyright 2000-2001 VA Linux Systems, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 * Gareth Hughes <gareth@valinux.com>
27 */
28 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgaioctl.c,v 1.16 2002/12/16 16:18:52 dawes Exp $ */
29
30 #include <errno.h>
31 #include "mtypes.h"
32 #include "macros.h"
33 #include "dd.h"
34 #include "swrast/swrast.h"
35
36 #include "mm.h"
37 #include "drm.h"
38 #include "mga_drm.h"
39 #include "mgacontext.h"
40 #include "mgadd.h"
41 #include "mgastate.h"
42 #include "mgatex.h"
43 #include "mgavb.h"
44 #include "mgaioctl.h"
45 #include "mgatris.h"
46
47 #include "vblank.h"
48
49
50 static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
51 unsigned long dest,
52 int length)
53 {
54 drmBufPtr buf = mmesa->iload_buffer;
55 drm_mga_iload_t iload;
56 int ret, i;
57
58 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
59 fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
60 buf->idx, (int) dest, length);
61
62 if ( (length & MGA_ILOAD_MASK) != 0 ) {
63 UNLOCK_HARDWARE( mmesa );
64 fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be "
65 "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN );
66 exit( 1 );
67 }
68
69 iload.idx = buf->idx;
70 iload.dstorg = dest;
71 iload.length = length;
72
73 i = 0;
74 do {
75 ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD,
76 &iload, sizeof(iload) );
77 } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
78
79 if ( ret < 0 ) {
80 printf("send iload retcode = %d\n", ret);
81 exit(1);
82 }
83
84 mmesa->iload_buffer = 0;
85
86 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
87 fprintf(stderr, "finished iload dma put\n");
88
89 }
90
91 drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa )
92 {
93 int idx = 0;
94 int size = 0;
95 drmDMAReq dma;
96 int retcode;
97 drmBufPtr buf;
98
99 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
100 fprintf(stderr, "Getting dma buffer\n");
101
102 dma.context = mmesa->hHWContext;
103 dma.send_count = 0;
104 dma.send_list = NULL;
105 dma.send_sizes = NULL;
106 dma.flags = 0;
107 dma.request_count = 1;
108 dma.request_size = MGA_BUFFER_SIZE;
109 dma.request_list = &idx;
110 dma.request_sizes = &size;
111 dma.granted_count = 0;
112
113
114 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
115 fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
116 dma.context, dma.request_count,
117 dma.request_size);
118
119 while (1) {
120 retcode = drmDMA(mmesa->driFd, &dma);
121
122 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
123 fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
124 retcode,
125 dma.request_sizes[0],
126 dma.request_list[0],
127 dma.granted_count);
128
129 if (retcode == 0 &&
130 dma.request_sizes[0] &&
131 dma.granted_count)
132 break;
133
134 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
135 fprintf(stderr, "\n\nflush");
136
137 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
138 }
139
140 buf = &(mmesa->mgaScreen->bufs->list[idx]);
141 buf->used = 0;
142
143 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
144 fprintf(stderr,
145 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
146 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
147 dma.request_sizes[0], dma.request_list[0],
148 buf->idx, buf->total,
149 buf->used, buf->address);
150
151 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
152 fprintf(stderr, "finished getbuffer\n");
153
154 return buf;
155 }
156
157
158
159
160 static void
161 mgaClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
162 GLint cx, GLint cy, GLint cw, GLint ch )
163 {
164 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
165 __DRIdrawablePrivate *dPriv = mmesa->driDrawable;
166 GLuint flags = 0;
167 GLuint clear_color = mmesa->ClearColor;
168 GLuint clear_depth = 0;
169 GLuint color_mask = 0;
170 GLuint depth_mask = 0;
171 int ret;
172 int i;
173 static int nrclears;
174 drm_mga_clear_t clear;
175
176 FLUSH_BATCH( mmesa );
177
178 if ( mask & DD_FRONT_LEFT_BIT ) {
179 flags |= MGA_FRONT;
180 color_mask = mmesa->setup.plnwt;
181 mask &= ~DD_FRONT_LEFT_BIT;
182 }
183
184 if ( mask & DD_BACK_LEFT_BIT ) {
185 flags |= MGA_BACK;
186 color_mask = mmesa->setup.plnwt;
187 mask &= ~DD_BACK_LEFT_BIT;
188 }
189
190 if ( (mask & DD_DEPTH_BIT) && ctx->Depth.Mask ) {
191 flags |= MGA_DEPTH;
192 clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask);
193 depth_mask |= mmesa->depth_clear_mask;
194 mask &= ~DD_DEPTH_BIT;
195 }
196
197 if ( (mask & DD_STENCIL_BIT) && mmesa->hw_stencil ) {
198 flags |= MGA_DEPTH;
199 clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask);
200 depth_mask |= mmesa->stencil_clear_mask;
201 mask &= ~DD_STENCIL_BIT;
202 }
203
204 if ( flags ) {
205 LOCK_HARDWARE( mmesa );
206
207 if ( mmesa->dirty_cliprects )
208 mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) );
209
210 /* flip top to bottom */
211 cy = dPriv->h-cy-ch;
212 cx += mmesa->drawX;
213 cy += mmesa->drawY;
214
215 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
216 fprintf( stderr, "Clear, bufs %x nbox %d\n",
217 (int)flags, (int)mmesa->numClipRects );
218
219 for (i = 0 ; i < mmesa->numClipRects ; )
220 {
221 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, mmesa->numClipRects);
222 drm_clip_rect_t *box = mmesa->pClipRects;
223 drm_clip_rect_t *b = mmesa->sarea->boxes;
224 int n = 0;
225
226 if (!all) {
227 for ( ; i < nr ; i++) {
228 GLint x = box[i].x1;
229 GLint y = box[i].y1;
230 GLint w = box[i].x2 - x;
231 GLint h = box[i].y2 - y;
232
233 if (x < cx) w -= cx - x, x = cx;
234 if (y < cy) h -= cy - y, y = cy;
235 if (x + w > cx + cw) w = cx + cw - x;
236 if (y + h > cy + ch) h = cy + ch - y;
237 if (w <= 0) continue;
238 if (h <= 0) continue;
239
240 b->x1 = x;
241 b->y1 = y;
242 b->x2 = x + w;
243 b->y2 = y + h;
244 b++;
245 n++;
246 }
247 } else {
248 for ( ; i < nr ; i++) {
249 *b++ = box[i];
250 n++;
251 }
252 }
253
254
255 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
256 fprintf( stderr,
257 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
258 flags, clear_color, clear_depth, mmesa->sarea->nbox );
259
260 mmesa->sarea->nbox = n;
261
262 clear.flags = flags;
263 clear.clear_color = clear_color;
264 clear.clear_depth = clear_depth;
265 clear.color_mask = color_mask;
266 clear.depth_mask = depth_mask;
267 ret = drmCommandWrite( mmesa->driFd, DRM_MGA_CLEAR,
268 &clear, sizeof(clear));
269 if ( ret ) {
270 fprintf( stderr, "send clear retcode = %d\n", ret );
271 exit( 1 );
272 }
273 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
274 fprintf( stderr, "finished clear %d\n", ++nrclears );
275 }
276
277 UNLOCK_HARDWARE( mmesa );
278 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT;
279 }
280
281 if (mask)
282 _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
283 }
284
285
286 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
287 {
288 unsigned wait = 0;
289 GLuint last_frame, last_wrap;
290
291
292 last_frame = mmesa->sarea->last_frame.head;
293 last_wrap = mmesa->sarea->last_frame.wrap;
294
295 /* FIXME: Add a timeout to this loop...
296 */
297 while ( 1 ) {
298 if ( last_wrap < mmesa->sarea->last_wrap ||
299 ( last_wrap == mmesa->sarea->last_wrap &&
300 last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) -
301 mmesa->primary_offset) ) ) {
302 break;
303 }
304 if ( 0 ) {
305 wait++;
306 fprintf( stderr, " last: head=0x%06x wrap=%d\n",
307 last_frame, last_wrap );
308 fprintf( stderr, " head: head=0x%06lx wrap=%d\n",
309 (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset),
310 mmesa->sarea->last_wrap );
311 }
312 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
313
314 UNLOCK_HARDWARE( mmesa );
315 DO_USLEEP( 1 );
316 LOCK_HARDWARE( mmesa );
317 }
318 if ( wait )
319 fprintf( stderr, "\n" );
320 }
321
322
323 /*
324 * Copy the back buffer to the front buffer.
325 */
326 void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv )
327 {
328 mgaContextPtr mmesa;
329 drm_clip_rect_t *pbox;
330 GLint nbox;
331 GLint ret;
332 GLint i;
333 GLboolean missed_target;
334
335
336 assert(dPriv);
337 assert(dPriv->driContextPriv);
338 assert(dPriv->driContextPriv->driverPrivate);
339
340 mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
341
342 FLUSH_BATCH( mmesa );
343
344 LOCK_HARDWARE( mmesa );
345 mgaWaitForFrameCompletion( mmesa );
346 UNLOCK_HARDWARE( mmesa );
347 driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags,
348 & missed_target );
349 if ( missed_target ) {
350 mmesa->swap_missed_count++;
351 (void) (*mmesa->get_ust)( & mmesa->swap_missed_ust );
352 }
353 LOCK_HARDWARE( mmesa );
354
355 /* Use the frontbuffer cliprects
356 */
357 if (mmesa->dirty_cliprects & MGA_FRONT)
358 mgaUpdateRects( mmesa, MGA_FRONT );
359
360
361 pbox = dPriv->pClipRects;
362 nbox = dPriv->numClipRects;
363
364 for (i = 0 ; i < nbox ; )
365 {
366 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
367 drm_clip_rect_t *b = mmesa->sarea->boxes;
368
369 mmesa->sarea->nbox = nr - i;
370
371 for ( ; i < nr ; i++)
372 *b++ = pbox[i];
373
374 if (0)
375 fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n");
376
377 ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP );
378 if ( ret ) {
379 printf("send swap retcode = %d\n", ret);
380 exit(1);
381 }
382 }
383
384 UNLOCK_HARDWARE( mmesa );
385
386 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
387 mmesa->swap_count++;
388 (void) (*mmesa->get_ust)( & mmesa->swap_ust );
389 }
390
391
392 /* This is overkill
393 */
394 static void mgaFinish( GLcontext *ctx )
395 {
396 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
397
398 FLUSH_BATCH( mmesa );
399
400 if (1/*mmesa->sarea->last_quiescent != mmesa->sarea->last_enqueue*/) {
401 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
402 fprintf(stderr, "mgaRegetLockQuiescent\n");
403
404 LOCK_HARDWARE( mmesa );
405 UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
406 UNLOCK_HARDWARE( mmesa );
407
408 mmesa->sarea->last_quiescent = mmesa->sarea->last_enqueue;
409 }
410 }
411
412 void mgaWaitAgeLocked( mgaContextPtr mmesa, int age )
413 {
414 if (GET_DISPATCH_AGE(mmesa) < age) {
415 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
416 }
417 }
418
419
420 void mgaWaitAge( mgaContextPtr mmesa, int age )
421 {
422 if (GET_DISPATCH_AGE(mmesa) < age) {
423 LOCK_HARDWARE(mmesa);
424 if (GET_DISPATCH_AGE(mmesa) < age) {
425 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
426 }
427 UNLOCK_HARDWARE(mmesa);
428 }
429 }
430
431
432 static GLboolean intersect_rect( drm_clip_rect_t *out,
433 const drm_clip_rect_t *a,
434 const drm_clip_rect_t *b )
435 {
436 *out = *a;
437 if (b->x1 > out->x1) out->x1 = b->x1;
438 if (b->y1 > out->y1) out->y1 = b->y1;
439 if (b->x2 < out->x2) out->x2 = b->x2;
440 if (b->y2 < out->y2) out->y2 = b->y2;
441
442 return ((out->x1 < out->x2) && (out->y1 < out->y2));
443 }
444
445
446
447
448 static void age_mmesa( mgaContextPtr mmesa, int age )
449 {
450 if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age;
451 if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age;
452 }
453
454 #ifdef __i386__
455 static int __break_vertex = 0;
456 #endif
457
458 void mgaFlushVerticesLocked( mgaContextPtr mmesa )
459 {
460 drm_clip_rect_t *pbox = mmesa->pClipRects;
461 int nbox = mmesa->numClipRects;
462 drmBufPtr buffer = mmesa->vertex_dma_buffer;
463 drm_mga_vertex_t vertex;
464 int i;
465
466 mmesa->vertex_dma_buffer = 0;
467
468 if (!buffer)
469 return;
470
471 if (mmesa->dirty_cliprects & mmesa->draw_buffer)
472 mgaUpdateRects( mmesa, mmesa->draw_buffer );
473
474 if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS)
475 mgaEmitHwStateLocked( mmesa );
476
477 /* FIXME: Workaround bug in kernel module.
478 */
479 mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
480
481 if (!nbox)
482 buffer->used = 0;
483
484 if (nbox >= MGA_NR_SAREA_CLIPRECTS)
485 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
486
487 #if 0
488 if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS))
489 {
490 if (nbox == 1)
491 mmesa->sarea->nbox = 0;
492 else
493 mmesa->sarea->nbox = nbox;
494
495 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
496 fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox);
497
498 vertex.idx = buffer->idx;
499 vertex.used = buffer->used;
500 vertex.discard = 1;
501 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
502 &vertex, sizeof(drmMGAVertex) );
503
504 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
505 }
506 else
507 #endif
508 {
509 for (i = 0 ; i < nbox ; )
510 {
511 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox);
512 drm_clip_rect_t *b = mmesa->sarea->boxes;
513 int discard = 0;
514
515 if (mmesa->scissor) {
516 mmesa->sarea->nbox = 0;
517
518 for ( ; i < nr ; i++) {
519 *b = pbox[i];
520 if (intersect_rect(b, b, &mmesa->scissor_rect)) {
521 mmesa->sarea->nbox++;
522 b++;
523 }
524 }
525
526 /* Culled?
527 */
528 if (!mmesa->sarea->nbox) {
529 if (nr < nbox) continue;
530 buffer->used = 0;
531 }
532 } else {
533 mmesa->sarea->nbox = nr - i;
534 for ( ; i < nr ; i++)
535 *b++ = pbox[i];
536 }
537
538 /* Finished with the buffer?
539 */
540 if (nr == nbox)
541 discard = 1;
542
543 mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS;
544
545 vertex.idx = buffer->idx;
546 vertex.used = buffer->used;
547 vertex.discard = discard;
548 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
549 &vertex, sizeof(vertex) );
550
551 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
552 }
553 }
554
555 /* Do we really need to do this ? */
556 #ifdef __i386__
557 if ( __break_vertex ) {
558 __asm__ __volatile__ ( "int $3" );
559 }
560 #endif
561
562 mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS;
563 }
564
565 void mgaFlushVertices( mgaContextPtr mmesa )
566 {
567 LOCK_HARDWARE( mmesa );
568 mgaFlushVerticesLocked( mmesa );
569 UNLOCK_HARDWARE( mmesa );
570 }
571
572
573 void mgaFireILoadLocked( mgaContextPtr mmesa,
574 GLuint offset, GLuint length )
575 {
576 if (!mmesa->iload_buffer) {
577 fprintf(stderr, "mgaFireILoad: no buffer\n");
578 return;
579 }
580
581 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
582 fprintf(stderr, "mgaFireILoad idx %d ofs 0x%x length %d\n",
583 mmesa->iload_buffer->idx, (int)offset, (int)length );
584
585 mga_iload_dma_ioctl( mmesa, offset, length );
586 }
587
588 void mgaGetILoadBufferLocked( mgaContextPtr mmesa )
589 {
590 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
591 fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n",
592 (void *) mmesa->iload_buffer);
593
594 mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa );
595 }
596
597 drmBufPtr mgaGetBufferLocked( mgaContextPtr mmesa )
598 {
599 return mga_get_buffer_ioctl( mmesa );
600 }
601
602
603
604 static void mgaFlush( GLcontext *ctx )
605 {
606 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
607
608
609 FLUSH_BATCH( mmesa );
610
611 /* This may be called redundantly - dispatch_age may trail what
612 * has actually been sent and processed by the hardware.
613 */
614 if (1 || GET_DISPATCH_AGE( mmesa ) < mmesa->sarea->last_enqueue) {
615 LOCK_HARDWARE( mmesa );
616 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
617 UNLOCK_HARDWARE( mmesa );
618 }
619 }
620
621
622
623
624 void mgaReleaseBufLocked( mgaContextPtr mmesa, drmBufPtr buffer )
625 {
626 drm_mga_vertex_t vertex;
627
628 if (!buffer) return;
629
630 vertex.idx = buffer->idx;
631 vertex.used = 0;
632 vertex.discard = 1;
633 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
634 &vertex, sizeof(vertex) );
635 }
636
637 int mgaFlushDMA( int fd, drmLockFlags flags )
638 {
639 drm_lock_t lock;
640 int ret, i = 0;
641
642 memset( &lock, 0, sizeof(lock) );
643
644 if ( flags & DRM_LOCK_QUIESCENT ) lock.flags |= DRM_LOCK_QUIESCENT;
645 if ( flags & DRM_LOCK_FLUSH ) lock.flags |= DRM_LOCK_FLUSH;
646 if ( flags & DRM_LOCK_FLUSH_ALL ) lock.flags |= DRM_LOCK_FLUSH_ALL;
647
648 do {
649 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
650 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
651
652 if ( ret == 0 )
653 return 0;
654 if ( errno != EBUSY )
655 return -errno;
656
657 if ( lock.flags & DRM_LOCK_QUIESCENT ) {
658 /* Only keep trying if we need quiescence.
659 */
660 lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL);
661
662 do {
663 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
664 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
665 }
666
667 if ( ret == 0 ) {
668 return 0;
669 } else {
670 return -errno;
671 }
672 }
673
674 void mgaInitIoctlFuncs( struct dd_function_table *functions )
675 {
676 functions->Clear = mgaClear;
677 functions->Flush = mgaFlush;
678 functions->Finish = mgaFinish;
679 }